@operato/twin-kernel 0.6.9 → 0.6.11
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.js +27 -3
- package/dist-cjs/index.cjs +13 -3
- package/package.json +1 -1
package/dist/flow-engine.js
CHANGED
|
@@ -186,7 +186,16 @@ nowIso) {
|
|
|
186
186
|
* 이벤트 누적기(근사)로 별도 공급해야 한다. 공식만 공유되고 입력원은 live 데이터-생산 결정.
|
|
187
187
|
*/
|
|
188
188
|
export function computeOee(c, nowMs) {
|
|
189
|
-
|
|
189
|
+
/*
|
|
190
|
+
* **계측 창을 모르면 잰 시간이 없다** — `?? 0` 으로 메우면 "1970년부터 재고 있었다" 가 된다.
|
|
191
|
+
*
|
|
192
|
+
* 그 결과가 화면까지 갔다: 갓 뜬 트윈의 절단기가 `idleMs 1767226603000`(약 56,000년) 유휴로 섰다.
|
|
193
|
+
* 시각을 소요시간 자리에 앉힌 것이고, 같은 값이 availability·overall 의 분모라 **성과 숫자 전체가
|
|
194
|
+
* 조용히 거짓**이 된다(가동률 100%, 성능 0%).
|
|
195
|
+
*
|
|
196
|
+
* 모르면 0 이 아니라 **없음**이다: 잰 구간이 없으면 유휴도 없다(아직 아무것도 재지 않았다).
|
|
197
|
+
*/
|
|
198
|
+
const planned = c.metricsSinceMs == null ? 0 : Math.max(0, nowMs - c.metricsSinceMs - (c.holdMs ?? 0));
|
|
190
199
|
const uptime = Math.max(0, planned - c.setupMs - c.downMs); // 가용시간(셋업·고장 제외)
|
|
191
200
|
const availability = planned > 0 ? uptime / planned : 1;
|
|
192
201
|
const performance = uptime > 0 ? Math.min(1, c.runMs / uptime) : (c.runMs > 0 ? 1 : 0);
|
|
@@ -369,7 +378,9 @@ export class FlowEngine {
|
|
|
369
378
|
};
|
|
370
379
|
}
|
|
371
380
|
buildEquipment(m) {
|
|
372
|
-
|
|
381
|
+
/* **계측은 이 자원이 모델에 들어온 순간부터** 잰다(`metricsSinceMs`). 빠뜨리면 공식이 창을 모르고,
|
|
382
|
+
예전에는 그것을 epoch 로 메워 갓 뜬 설비가 56,000년 유휴로 보였다(§computeOee). */
|
|
383
|
+
const eq = { id: m.id, kind: m.kind, location: m.homeLocation, homeLocation: m.homeLocation, ...(m.properties ? { properties: m.properties } : {}), ...(m.testSpecificationIds ? { testSpecificationIds: m.testSpecificationIds } : {}), ...(m.testResults ? { testResults: m.testResults } : {}), status: 'idle', taskId: null, runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0, metricsSinceMs: this.clockMs, window: m.window, ...(m.workCalendar ? { workCalendar: m.workCalendar } : {}), ...effectiveOnly(m) };
|
|
373
384
|
if (m.mtbfMs !== undefined) {
|
|
374
385
|
eq.mtbfMs = m.mtbfMs;
|
|
375
386
|
eq.mttrMs = m.mttrMs;
|
|
@@ -384,7 +395,7 @@ export class FlowEngine {
|
|
|
384
395
|
addEquipment(m) {
|
|
385
396
|
if (this.equipment.has(m.id))
|
|
386
397
|
return;
|
|
387
|
-
const eq = { id: m.id, kind: m.kind, location: m.homeLocation, homeLocation: m.homeLocation, ...(m.properties ? { properties: m.properties } : {}), ...(m.testSpecificationIds ? { testSpecificationIds: m.testSpecificationIds } : {}), ...(m.testResults ? { testResults: m.testResults } : {}), status: 'idle', taskId: null, runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0 };
|
|
398
|
+
const eq = { id: m.id, kind: m.kind, location: m.homeLocation, homeLocation: m.homeLocation, ...(m.properties ? { properties: m.properties } : {}), ...(m.testSpecificationIds ? { testSpecificationIds: m.testSpecificationIds } : {}), ...(m.testResults ? { testResults: m.testResults } : {}), status: 'idle', taskId: null, runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0, metricsSinceMs: this.clockMs };
|
|
388
399
|
if (m.mtbfMs !== undefined) {
|
|
389
400
|
eq.mtbfMs = m.mtbfMs;
|
|
390
401
|
eq.mttrMs = m.mttrMs;
|
|
@@ -452,6 +463,7 @@ export class FlowEngine {
|
|
|
452
463
|
* 한계가 있다 — busy 를 가동으로 근사하고 **셋업을 분리하지 못해 0** 으로 둔다. 여기서는 받은
|
|
453
464
|
* 값을 그대로 이어받고, 없으면 0 에서 시작한다(꾸미지 않는다).
|
|
454
465
|
*/
|
|
466
|
+
/* `idleMs` 까지 읽는다 — 그것이 있어야 **잰 구간**을 되세울 수 있다(계획 시간 = 가동+준비+고장+유휴). */
|
|
455
467
|
const oee = m.oee;
|
|
456
468
|
/* **마스터가 말한 것을 관측이 지우지 않는다.** 예전에는 이 자리에서 통째로 새 객체를 만들어
|
|
457
469
|
* 교대 캘린더·속성·유효 기간·계획정지를 **전부 버렸다.** 그 결과 라이브(관측) 커널은
|
|
@@ -463,6 +475,18 @@ export class FlowEngine {
|
|
|
463
475
|
id: m.id, kind: m.kind, location: m.location ?? '', ...(m.homeLocation ? { homeLocation: m.homeLocation } : {}), status: m.status ?? 'idle', taskId: null,
|
|
464
476
|
runMs: oee?.runMs ?? 0, setupMs: oee?.setupMs ?? 0, downMs: oee?.downMs ?? 0,
|
|
465
477
|
goodCount: oee?.goodCount ?? 0, scrapCount: oee?.scrapCount ?? 0,
|
|
478
|
+
/*
|
|
479
|
+
* **잰 값을 이어받으면 잰 구간도 이어받아야 한다.**
|
|
480
|
+
*
|
|
481
|
+
* 카운터만 되살리고 창을 지금으로 두면 둘이 어긋난다: 이어받은 가동 8시간이 방금 시작한 창
|
|
482
|
+
* 안에 앉아, 놀고 있는 설비가 **가동률 100%·유휴 0초**로 보인다(화면에서 관측됨).
|
|
483
|
+
*
|
|
484
|
+
* 창은 지표 자신이 말해 준다 — 계획 시간은 가동·준비·고장·유휴의 합이다. 그래서 그 합만큼
|
|
485
|
+
* 뒤로 물려 창을 다시 세운다. 지표가 없으면 창도 없다(그때는 지금부터 새로 잰다).
|
|
486
|
+
*/
|
|
487
|
+
...(oee
|
|
488
|
+
? { metricsSinceMs: this.clockMs - ((oee.runMs ?? 0) + (oee.setupMs ?? 0) + (oee.downMs ?? 0) + (oee.idleMs ?? 0)) }
|
|
489
|
+
: {}),
|
|
466
490
|
/* 계획 정지를 이어받는다 — 잃으면 씨앗이 **정비 중인 설비를 가용으로 놓고** 미래를 굴린다
|
|
467
491
|
(예측이 낙관 쪽으로 치우친다). 씨앗 왕복 대조가 이것을 잡았다. */
|
|
468
492
|
...(m.held ? { held: true } : {}),
|
package/dist-cjs/index.cjs
CHANGED
|
@@ -2370,7 +2370,7 @@ function deriveAttentions(view, acked, nowIso) {
|
|
|
2370
2370
|
return out;
|
|
2371
2371
|
}
|
|
2372
2372
|
function computeOee(c, nowMs) {
|
|
2373
|
-
const planned = Math.max(0, nowMs -
|
|
2373
|
+
const planned = c.metricsSinceMs == null ? 0 : Math.max(0, nowMs - c.metricsSinceMs - (c.holdMs ?? 0));
|
|
2374
2374
|
const uptime = Math.max(0, planned - c.setupMs - c.downMs);
|
|
2375
2375
|
const availability = planned > 0 ? uptime / planned : 1;
|
|
2376
2376
|
const performance = uptime > 0 ? Math.min(1, c.runMs / uptime) : c.runMs > 0 ? 1 : 0;
|
|
@@ -2555,7 +2555,7 @@ var FlowEngine = class {
|
|
|
2555
2555
|
};
|
|
2556
2556
|
}
|
|
2557
2557
|
buildEquipment(m) {
|
|
2558
|
-
const eq = { id: m.id, kind: m.kind, location: m.homeLocation, homeLocation: m.homeLocation, ...m.properties ? { properties: m.properties } : {}, ...m.testSpecificationIds ? { testSpecificationIds: m.testSpecificationIds } : {}, ...m.testResults ? { testResults: m.testResults } : {}, status: "idle", taskId: null, runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0, window: m.window, ...m.workCalendar ? { workCalendar: m.workCalendar } : {}, ...effectiveOnly(m) };
|
|
2558
|
+
const eq = { id: m.id, kind: m.kind, location: m.homeLocation, homeLocation: m.homeLocation, ...m.properties ? { properties: m.properties } : {}, ...m.testSpecificationIds ? { testSpecificationIds: m.testSpecificationIds } : {}, ...m.testResults ? { testResults: m.testResults } : {}, status: "idle", taskId: null, runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0, metricsSinceMs: this.clockMs, window: m.window, ...m.workCalendar ? { workCalendar: m.workCalendar } : {}, ...effectiveOnly(m) };
|
|
2559
2559
|
if (m.mtbfMs !== void 0) {
|
|
2560
2560
|
eq.mtbfMs = m.mtbfMs;
|
|
2561
2561
|
eq.mttrMs = m.mttrMs;
|
|
@@ -2569,7 +2569,7 @@ var FlowEngine = class {
|
|
|
2569
2569
|
*/
|
|
2570
2570
|
addEquipment(m) {
|
|
2571
2571
|
if (this.equipment.has(m.id)) return;
|
|
2572
|
-
const eq = { id: m.id, kind: m.kind, location: m.homeLocation, homeLocation: m.homeLocation, ...m.properties ? { properties: m.properties } : {}, ...m.testSpecificationIds ? { testSpecificationIds: m.testSpecificationIds } : {}, ...m.testResults ? { testResults: m.testResults } : {}, status: "idle", taskId: null, runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0 };
|
|
2572
|
+
const eq = { id: m.id, kind: m.kind, location: m.homeLocation, homeLocation: m.homeLocation, ...m.properties ? { properties: m.properties } : {}, ...m.testSpecificationIds ? { testSpecificationIds: m.testSpecificationIds } : {}, ...m.testResults ? { testResults: m.testResults } : {}, status: "idle", taskId: null, runMs: 0, setupMs: 0, downMs: 0, goodCount: 0, scrapCount: 0, metricsSinceMs: this.clockMs };
|
|
2573
2573
|
if (m.mtbfMs !== void 0) {
|
|
2574
2574
|
eq.mtbfMs = m.mtbfMs;
|
|
2575
2575
|
eq.mttrMs = m.mttrMs;
|
|
@@ -2639,6 +2639,16 @@ var FlowEngine = class {
|
|
|
2639
2639
|
downMs: oee?.downMs ?? 0,
|
|
2640
2640
|
goodCount: oee?.goodCount ?? 0,
|
|
2641
2641
|
scrapCount: oee?.scrapCount ?? 0,
|
|
2642
|
+
/*
|
|
2643
|
+
* **잰 값을 이어받으면 잰 구간도 이어받아야 한다.**
|
|
2644
|
+
*
|
|
2645
|
+
* 카운터만 되살리고 창을 지금으로 두면 둘이 어긋난다: 이어받은 가동 8시간이 방금 시작한 창
|
|
2646
|
+
* 안에 앉아, 놀고 있는 설비가 **가동률 100%·유휴 0초**로 보인다(화면에서 관측됨).
|
|
2647
|
+
*
|
|
2648
|
+
* 창은 지표 자신이 말해 준다 — 계획 시간은 가동·준비·고장·유휴의 합이다. 그래서 그 합만큼
|
|
2649
|
+
* 뒤로 물려 창을 다시 세운다. 지표가 없으면 창도 없다(그때는 지금부터 새로 잰다).
|
|
2650
|
+
*/
|
|
2651
|
+
...oee ? { metricsSinceMs: this.clockMs - ((oee.runMs ?? 0) + (oee.setupMs ?? 0) + (oee.downMs ?? 0) + (oee.idleMs ?? 0)) } : {},
|
|
2642
2652
|
/* 계획 정지를 이어받는다 — 잃으면 씨앗이 **정비 중인 설비를 가용으로 놓고** 미래를 굴린다
|
|
2643
2653
|
(예측이 낙관 쪽으로 치우친다). 씨앗 왕복 대조가 이것을 잡았다. */
|
|
2644
2654
|
...m.held ? { held: true } : {},
|
package/package.json
CHANGED