@operato/twin-kernel 0.7.11 → 0.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contract.d.ts +28 -0
- package/dist/flow-engine.js +15 -3
- package/dist/observed-reducer.js +4 -0
- package/dist/yms-kernel.d.ts +2 -0
- package/dist/yms-kernel.js +21 -1
- package/dist-cjs/index.cjs +31 -4
- package/package.json +1 -1
package/dist/contract.d.ts
CHANGED
|
@@ -1125,6 +1125,20 @@ export interface OrderState {
|
|
|
1125
1125
|
* 이것도 상태에 없어서 되살아난 오더는 빈 문자열을 갖고, 이후 모든 이벤트의 거래번호가 빈다.
|
|
1126
1126
|
*/
|
|
1127
1127
|
bizTransaction?: string;
|
|
1128
|
+
/**
|
|
1129
|
+
* 도메인이 **약속해 둔 자리와 시각창** — 어디로/언제 들이기로 했는가.
|
|
1130
|
+
*
|
|
1131
|
+
* ── 왜 사실에 실어야 하나 (2026-08-17) ─────────────────────────────────────
|
|
1132
|
+
* 야드 트윈이 재기동 뒤 **첫 틱에서 죽었다.** 어포인트먼트를 받을 때 도크 도어를 정해 두는데
|
|
1133
|
+
* 그것이 어느 사실에도 실리지 않아, 웜스타트가 오더는 되살리고 배정은 잃었다. 그리고 다음 틱에
|
|
1134
|
+
* 「그 도어의 점유」를 읽다 예외가 났다(`Cannot read properties of undefined`). 안전망이 그 트윈만
|
|
1135
|
+
* 세워 다른 트윈은 살았지만, 야드 트윈 셋이 부팅마다 죽는 상태였다.
|
|
1136
|
+
*
|
|
1137
|
+
* `allocated` 가 두 자리에만 있어 계보를 잃었던 것과 **같은 부류**다: 상태가 필요로 하는 것을
|
|
1138
|
+
* 사실이 갖고 있지 않으면 재기동을 넘지 못한다.
|
|
1139
|
+
*/
|
|
1140
|
+
dockDoor?: string;
|
|
1141
|
+
windowStartMs?: number;
|
|
1128
1142
|
/** 우선순위 — 표준 `OperationsRequest.Priority`. 작은 값이 급하다. 오더 할당 순서를 정한다. */
|
|
1129
1143
|
priority?: number;
|
|
1130
1144
|
/** 예정 착수 — 표준 `OperationsRequest.StartTime`. */
|
|
@@ -1670,6 +1684,20 @@ export interface OrderStatusDelta {
|
|
|
1670
1684
|
*/
|
|
1671
1685
|
allocated?: string[];
|
|
1672
1686
|
bizTransaction?: string;
|
|
1687
|
+
/**
|
|
1688
|
+
* 도메인이 **약속해 둔 자리와 시각창** — 어디로/언제 들이기로 했는가.
|
|
1689
|
+
*
|
|
1690
|
+
* ── 왜 사실에 실어야 하나 (2026-08-17) ─────────────────────────────────────
|
|
1691
|
+
* 야드 트윈이 재기동 뒤 **첫 틱에서 죽었다.** 어포인트먼트를 받을 때 도크 도어를 정해 두는데
|
|
1692
|
+
* 그것이 어느 사실에도 실리지 않아, 웜스타트가 오더는 되살리고 배정은 잃었다. 그리고 다음 틱에
|
|
1693
|
+
* 「그 도어의 점유」를 읽다 예외가 났다(`Cannot read properties of undefined`). 안전망이 그 트윈만
|
|
1694
|
+
* 세워 다른 트윈은 살았지만, 야드 트윈 셋이 부팅마다 죽는 상태였다.
|
|
1695
|
+
*
|
|
1696
|
+
* `allocated` 가 두 자리에만 있어 계보를 잃었던 것과 **같은 부류**다: 상태가 필요로 하는 것을
|
|
1697
|
+
* 사실이 갖고 있지 않으면 재기동을 넘지 못한다.
|
|
1698
|
+
*/
|
|
1699
|
+
dockDoor?: string;
|
|
1700
|
+
windowStartMs?: number;
|
|
1673
1701
|
}
|
|
1674
1702
|
export declare const CMD: {
|
|
1675
1703
|
readonly orderHold: "order.hold";
|
package/dist/flow-engine.js
CHANGED
|
@@ -589,7 +589,9 @@ export class FlowEngine {
|
|
|
589
589
|
사라진다(같은 사실이 델타·스냅샷·이 변환 **세 길**을 지난다). */
|
|
590
590
|
...(o.allocated?.length ? { allocated: o.allocated } : {}),
|
|
591
591
|
...(o.gtin ? { gtin: o.gtin } : {}),
|
|
592
|
-
...(o.bizTransaction ? { bizTransaction: o.bizTransaction } : {})
|
|
592
|
+
...(o.bizTransaction ? { bizTransaction: o.bizTransaction } : {}),
|
|
593
|
+
...(o.dockDoor ? { dockDoor: o.dockDoor } : {}),
|
|
594
|
+
...(o.windowStartMs !== undefined ? { windowStartMs: o.windowStartMs } : {})
|
|
593
595
|
}));
|
|
594
596
|
for (const o of observedOrders) {
|
|
595
597
|
const lines = (o.lines ?? []).map(l => ({ gtin: l.gtin, requested: l.requested - (l.fulfilled ?? 0) })).filter(l => l.requested > 0);
|
|
@@ -614,7 +616,11 @@ export class FlowEngine {
|
|
|
614
616
|
...(o.held ? { held: true } : {}),
|
|
615
617
|
...(o.endTime ? { endTime: o.endTime } : {}),
|
|
616
618
|
...(o.startTime ? { startTime: o.startTime } : {}),
|
|
617
|
-
...(o.priority !== undefined ? { priority: o.priority } : {})
|
|
619
|
+
...(o.priority !== undefined ? { priority: o.priority } : {}),
|
|
620
|
+
/* 약속해 둔 자리·시각창을 이어받는다 — 없으면 도메인이 「정해 뒀다」고 믿는 것을 잃는다.
|
|
621
|
+
사실이 말해 주지 않으면(옛 저널) 비는 것이 사실이다 — 지어내지 않는다. */
|
|
622
|
+
...(o.dockDoor ? { dockDoor: o.dockDoor } : {}),
|
|
623
|
+
...(o.windowStartMs !== undefined ? { windowStartMs: o.windowStartMs } : {})
|
|
618
624
|
});
|
|
619
625
|
}
|
|
620
626
|
/* 작업이 딛고 설 오더를 먼저 세운다 — 순서가 뒤바뀌면 아래 확인이 언제나 "없다" 로 답한다. */
|
|
@@ -955,6 +961,9 @@ export class FlowEngine {
|
|
|
955
961
|
/* 진행 중 확보분과 거래번호 — **스냅샷에도** 실어야 한다. 델타에만 실으면 스냅샷으로
|
|
956
962
|
재기동하는 경로(체크포인트)에서 그대로 잃는다(같은 사실을 두 길로 나르는 값이다). */
|
|
957
963
|
...(o.allocated?.length ? { allocated: o.allocated.slice() } : {}),
|
|
964
|
+
/* 스냅샷도 함께 나른다 — 델타·스냅샷·복원 **세 길** 중 하나만 빠져도 재기동이 잃는다. */
|
|
965
|
+
...(o.dockDoor ? { dockDoor: o.dockDoor } : {}),
|
|
966
|
+
...(o.windowStartMs !== undefined ? { windowStartMs: o.windowStartMs } : {}),
|
|
958
967
|
...(o.bizTransaction ? { bizTransaction: o.bizTransaction } : {}),
|
|
959
968
|
held: o.held
|
|
960
969
|
})),
|
|
@@ -1660,7 +1669,10 @@ export class FlowEngine {
|
|
|
1660
1669
|
계보가 입력 없이 나간다(무엇이 무엇으로 바뀌었나의 절반이 사라진다). */
|
|
1661
1670
|
...(o.gtin ? { gtin: o.gtin } : {}),
|
|
1662
1671
|
...(o.allocated?.length ? { allocated: o.allocated.slice() } : {}),
|
|
1663
|
-
...(o.bizTransaction ? { bizTransaction: o.bizTransaction } : {})
|
|
1672
|
+
...(o.bizTransaction ? { bizTransaction: o.bizTransaction } : {}),
|
|
1673
|
+
/* 약속해 둔 자리·시각창 — 이것이 빠져서 야드 트윈이 재기동마다 첫 틱에 죽었다(§dockDoor). */
|
|
1674
|
+
...(o.dockDoor ? { dockDoor: o.dockDoor } : {}),
|
|
1675
|
+
...(o.windowStartMs !== undefined ? { windowStartMs: o.windowStartMs } : {})
|
|
1664
1676
|
});
|
|
1665
1677
|
}
|
|
1666
1678
|
// ── 내부 mechanics ─────────────────────────────────────────────────────────
|
package/dist/observed-reducer.js
CHANGED
|
@@ -357,6 +357,10 @@ export class ObservedReducer {
|
|
|
357
357
|
...(d.gtin ? { gtin: d.gtin } : {}),
|
|
358
358
|
...(d.allocated?.length ? { allocated: d.allocated.slice() } : {}),
|
|
359
359
|
...(d.bizTransaction ? { bizTransaction: d.bizTransaction } : {}),
|
|
360
|
+
/* 약속해 둔 자리·시각창도 채운다 — 시뮬만 알면 미러 위 예측이 「어디로 들일지」를 모른다.
|
|
361
|
+
(이 필드가 어느 길에서 빠지면 무슨 일이 나는지는 §dockDoor 에 적혀 있다.) */
|
|
362
|
+
...(d.dockDoor ? { dockDoor: d.dockDoor } : {}),
|
|
363
|
+
...(d.windowStartMs !== undefined ? { windowStartMs: d.windowStartMs } : {}),
|
|
360
364
|
held: d.held
|
|
361
365
|
});
|
|
362
366
|
break;
|
package/dist/yms-kernel.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export declare class YmsKernel extends FlowEngine {
|
|
|
8
8
|
private cargoSeq;
|
|
9
9
|
private trailerCargo;
|
|
10
10
|
private apptMode;
|
|
11
|
+
/** 도어를 못 찾아 대기시킨 오더 — 같은 말을 매 틱 반복하지 않기 위한 표시(§allocate). */
|
|
12
|
+
private doorWarned;
|
|
11
13
|
/** 야드 운영 정책(상하차 방식). 기본 drop(야드 버퍼). live 는 게이트/도크 직행. */
|
|
12
14
|
mode: YardMode;
|
|
13
15
|
constructor(tenantId: string, policy?: AllocationPolicy, mode?: YardMode);
|
package/dist/yms-kernel.js
CHANGED
|
@@ -39,6 +39,8 @@ export class YmsKernel extends FlowEngine {
|
|
|
39
39
|
cargoSeq = 0;
|
|
40
40
|
trailerCargo = new Map(); // 트레일러 epc → 화물 SSCC(하차 전 opaque / 상차 예약분)
|
|
41
41
|
apptMode = new Map(); // orderId → 상하차 모드(생성 시 캡처)
|
|
42
|
+
/** 도어를 못 찾아 대기시킨 오더 — 같은 말을 매 틱 반복하지 않기 위한 표시(§allocate). */
|
|
43
|
+
doorWarned = new Set();
|
|
42
44
|
/** 야드 운영 정책(상하차 방식). 기본 drop(야드 버퍼). live 는 게이트/도크 직행. */
|
|
43
45
|
mode;
|
|
44
46
|
constructor(tenantId, policy = firstFitPolicy, mode = 'drop') {
|
|
@@ -102,7 +104,25 @@ export class YmsKernel extends FlowEngine {
|
|
|
102
104
|
return;
|
|
103
105
|
if (this.clockMs < (o.windowStartMs ?? 0))
|
|
104
106
|
return; // 창 도래 전
|
|
105
|
-
|
|
107
|
+
/*
|
|
108
|
+
* ── 배정된 도어가 없으면 **기다린다** (2026-08-17) ────────────────────────
|
|
109
|
+
*
|
|
110
|
+
* 예전에는 `this.locations.get(o.dockDoor!)!` 였다. 그래서 배정을 모르는 오더가 들어오면 바로
|
|
111
|
+
* 아래에서 `undefined.occupancy` 를 읽고 **틱 전체가 예외로 죽었다** — 야드 트윈 셋이 재기동마다
|
|
112
|
+
* 그렇게 멈췄다(안전망이 세운 것이지 스스로 멈춘 것이 아니다).
|
|
113
|
+
*
|
|
114
|
+
* 이제 그 오더만 대기로 남기고 **왜인지 한 번 말한다.** 매 틱 말하면 로그가 그것만 남으므로 한 번만
|
|
115
|
+
* 말하고, 조용히 넘기지도 않는다 — 조용하면 「왜 이 오더는 영원히 안 움직이나」를 아무도 답할 수 없다.
|
|
116
|
+
*/
|
|
117
|
+
const door = o.dockDoor ? this.locations.get(o.dockDoor) : undefined;
|
|
118
|
+
if (!door) {
|
|
119
|
+
if (!this.doorWarned.has(o.id)) {
|
|
120
|
+
this.doorWarned.add(o.id);
|
|
121
|
+
console.warn(`[yms-kernel] order "${o.id}" waits: ${o.dockDoor ? `its dock door "${o.dockDoor}" is not in this model` : 'no dock door was assigned to it'}` +
|
|
122
|
+
' — the appointment cannot be scheduled until the declaration says where.');
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
106
126
|
const inflight = [...this.tasks.values()].some(t => t.status !== 'completed' && t.toNode === door.id);
|
|
107
127
|
if (door.occupancy > 0 || inflight)
|
|
108
128
|
return; // 도어 사용중/예약됨 → 대기(직렬화)
|
package/dist-cjs/index.cjs
CHANGED
|
@@ -1354,6 +1354,10 @@ var ObservedReducer = class {
|
|
|
1354
1354
|
...d.gtin ? { gtin: d.gtin } : {},
|
|
1355
1355
|
...d.allocated?.length ? { allocated: d.allocated.slice() } : {},
|
|
1356
1356
|
...d.bizTransaction ? { bizTransaction: d.bizTransaction } : {},
|
|
1357
|
+
/* 약속해 둔 자리·시각창도 채운다 — 시뮬만 알면 미러 위 예측이 「어디로 들일지」를 모른다.
|
|
1358
|
+
(이 필드가 어느 길에서 빠지면 무슨 일이 나는지는 §dockDoor 에 적혀 있다.) */
|
|
1359
|
+
...d.dockDoor ? { dockDoor: d.dockDoor } : {},
|
|
1360
|
+
...d.windowStartMs !== void 0 ? { windowStartMs: d.windowStartMs } : {},
|
|
1357
1361
|
held: d.held
|
|
1358
1362
|
});
|
|
1359
1363
|
break;
|
|
@@ -3219,7 +3223,9 @@ var FlowEngine = class {
|
|
|
3219
3223
|
사라진다(같은 사실이 델타·스냅샷·이 변환 **세 길**을 지난다). */
|
|
3220
3224
|
...o.allocated?.length ? { allocated: o.allocated } : {},
|
|
3221
3225
|
...o.gtin ? { gtin: o.gtin } : {},
|
|
3222
|
-
...o.bizTransaction ? { bizTransaction: o.bizTransaction } : {}
|
|
3226
|
+
...o.bizTransaction ? { bizTransaction: o.bizTransaction } : {},
|
|
3227
|
+
...o.dockDoor ? { dockDoor: o.dockDoor } : {},
|
|
3228
|
+
...o.windowStartMs !== void 0 ? { windowStartMs: o.windowStartMs } : {}
|
|
3223
3229
|
}));
|
|
3224
3230
|
for (const o of observedOrders) {
|
|
3225
3231
|
const lines = (o.lines ?? []).map((l) => ({ gtin: l.gtin, requested: l.requested - (l.fulfilled ?? 0) })).filter((l) => l.requested > 0);
|
|
@@ -3246,7 +3252,11 @@ var FlowEngine = class {
|
|
|
3246
3252
|
...o.held ? { held: true } : {},
|
|
3247
3253
|
...o.endTime ? { endTime: o.endTime } : {},
|
|
3248
3254
|
...o.startTime ? { startTime: o.startTime } : {},
|
|
3249
|
-
...o.priority !== void 0 ? { priority: o.priority } : {}
|
|
3255
|
+
...o.priority !== void 0 ? { priority: o.priority } : {},
|
|
3256
|
+
/* 약속해 둔 자리·시각창을 이어받는다 — 없으면 도메인이 「정해 뒀다」고 믿는 것을 잃는다.
|
|
3257
|
+
사실이 말해 주지 않으면(옛 저널) 비는 것이 사실이다 — 지어내지 않는다. */
|
|
3258
|
+
...o.dockDoor ? { dockDoor: o.dockDoor } : {},
|
|
3259
|
+
...o.windowStartMs !== void 0 ? { windowStartMs: o.windowStartMs } : {}
|
|
3250
3260
|
});
|
|
3251
3261
|
}
|
|
3252
3262
|
const seededOrderIds = new Set(this.orders.keys());
|
|
@@ -3562,6 +3572,9 @@ var FlowEngine = class {
|
|
|
3562
3572
|
/* 진행 중 확보분과 거래번호 — **스냅샷에도** 실어야 한다. 델타에만 실으면 스냅샷으로
|
|
3563
3573
|
재기동하는 경로(체크포인트)에서 그대로 잃는다(같은 사실을 두 길로 나르는 값이다). */
|
|
3564
3574
|
...o.allocated?.length ? { allocated: o.allocated.slice() } : {},
|
|
3575
|
+
/* 스냅샷도 함께 나른다 — 델타·스냅샷·복원 **세 길** 중 하나만 빠져도 재기동이 잃는다. */
|
|
3576
|
+
...o.dockDoor ? { dockDoor: o.dockDoor } : {},
|
|
3577
|
+
...o.windowStartMs !== void 0 ? { windowStartMs: o.windowStartMs } : {},
|
|
3565
3578
|
...o.bizTransaction ? { bizTransaction: o.bizTransaction } : {},
|
|
3566
3579
|
held: o.held
|
|
3567
3580
|
})),
|
|
@@ -4208,7 +4221,10 @@ var FlowEngine = class {
|
|
|
4208
4221
|
계보가 입력 없이 나간다(무엇이 무엇으로 바뀌었나의 절반이 사라진다). */
|
|
4209
4222
|
...o.gtin ? { gtin: o.gtin } : {},
|
|
4210
4223
|
...o.allocated?.length ? { allocated: o.allocated.slice() } : {},
|
|
4211
|
-
...o.bizTransaction ? { bizTransaction: o.bizTransaction } : {}
|
|
4224
|
+
...o.bizTransaction ? { bizTransaction: o.bizTransaction } : {},
|
|
4225
|
+
/* 약속해 둔 자리·시각창 — 이것이 빠져서 야드 트윈이 재기동마다 첫 틱에 죽었다(§dockDoor). */
|
|
4226
|
+
...o.dockDoor ? { dockDoor: o.dockDoor } : {},
|
|
4227
|
+
...o.windowStartMs !== void 0 ? { windowStartMs: o.windowStartMs } : {}
|
|
4212
4228
|
});
|
|
4213
4229
|
}
|
|
4214
4230
|
// ── 내부 mechanics ─────────────────────────────────────────────────────────
|
|
@@ -5300,6 +5316,8 @@ var YmsKernel = class extends FlowEngine {
|
|
|
5300
5316
|
// 트레일러 epc → 화물 SSCC(하차 전 opaque / 상차 예약분)
|
|
5301
5317
|
apptMode = /* @__PURE__ */ new Map();
|
|
5302
5318
|
// orderId → 상하차 모드(생성 시 캡처)
|
|
5319
|
+
/** 도어를 못 찾아 대기시킨 오더 — 같은 말을 매 틱 반복하지 않기 위한 표시(§allocate). */
|
|
5320
|
+
doorWarned = /* @__PURE__ */ new Set();
|
|
5303
5321
|
/** 야드 운영 정책(상하차 방식). 기본 drop(야드 버퍼). live 는 게이트/도크 직행. */
|
|
5304
5322
|
mode;
|
|
5305
5323
|
constructor(tenantId, policy = firstFitPolicy, mode = "drop") {
|
|
@@ -5371,7 +5389,16 @@ var YmsKernel = class extends FlowEngine {
|
|
|
5371
5389
|
const trailer = this.items.get(o.allocated[0]);
|
|
5372
5390
|
if (!trailer) return;
|
|
5373
5391
|
if (this.clockMs < (o.windowStartMs ?? 0)) return;
|
|
5374
|
-
const door = this.locations.get(o.dockDoor);
|
|
5392
|
+
const door = o.dockDoor ? this.locations.get(o.dockDoor) : void 0;
|
|
5393
|
+
if (!door) {
|
|
5394
|
+
if (!this.doorWarned.has(o.id)) {
|
|
5395
|
+
this.doorWarned.add(o.id);
|
|
5396
|
+
console.warn(
|
|
5397
|
+
`[yms-kernel] order "${o.id}" waits: ${o.dockDoor ? `its dock door "${o.dockDoor}" is not in this model` : "no dock door was assigned to it"} \u2014 the appointment cannot be scheduled until the declaration says where.`
|
|
5398
|
+
);
|
|
5399
|
+
}
|
|
5400
|
+
return;
|
|
5401
|
+
}
|
|
5375
5402
|
const inflight = [...this.tasks.values()].some((t) => t.status !== "completed" && t.toNode === door.id);
|
|
5376
5403
|
if (door.occupancy > 0 || inflight) return;
|
|
5377
5404
|
const mode = this.apptMode.get(o.id) ?? "drop";
|
package/package.json
CHANGED