import type { OeeCounters, WorkCalendarEntry } from '@operato/ops-contract'; import type { CanonicalEnvelope, OeeMetrics } from '@operato/ops-contract'; interface Acc { status?: string; lastMs: number; startMs: number; busyMs: number; downMs: number; goodCount: number; nonconformingCount: number; } /** 누적기의 완전한 재개점 — 저장했다 되살릴 수 있어야 꼬리만 계산할 수 있다. */ export interface OeeCheckpoint { maxMs: number; acc: ({ moverId: string; } & Acc)[]; } export declare class OeeAccumulator { private acc; private maxMs; private siteCalendar?; private calendarByResource; private utcOffsetMinutes?; /** * 모델에서 조업 달력을 읽어 얹는다 — 모델을 들고 있는 쪽(`TwinEngine`)이 부른다. * * ── 우선순위가 여기 있는 이유 ─────────────────────────────────────────────── * ``` * 설비의 달력 이 설비의 가동 계획 — 선언했으면 이것이 이긴다 (24시간 도는 로) * 현장의 달력 이 현장의 조업일 * 없음 제약 없음 — 계획 조업 시간이 창 전체가 된다 * ``` * 계획 조업 시간을 내는 자리가 여기라 그 규칙도 여기 둔다. 부르는 쪽마다 고르게 하면 라이브와 * 히스토리가 다른 답을 낸다. * * ⚠ **설비의 달력은 사람의 근무조가 아니다.** 씨앗이 사람의 근무조를 설비 달력에 복사한 일이 있었고, * 그때 아무도 근무하지 않는 시간이 근무 시간으로 기록됐다. 사람 쪽은 `persons[].workCalendar` 다. * * 세우는 자리에서 한 번만 주지 않고 따로 부르는 이유는 모델이 다시 실릴 수 있기 때문이다 * (재동기화 · 이관). 그때 달력만 갈아 끼우면 누적된 계측을 버리지 않는다. */ setWorkCalendar(model?: { workCalendar?: readonly WorkCalendarEntry[]; equipment?: readonly any[]; utcOffsetMinutes?: number; }): void; /** * 이 설비의 계획 가동 달력 — 자기 것이 있으면 그것, 없으면 현장의 것. * * 인자 이름이 `moverId` 인 것은 **봉투의 옛 세대 필드 이름**이라 그렇다(§`apply`). 새로 만드는 * 이름에는 그 낱말을 쓰지 않는다 — 어휘 가드가 그것을 잡았고, 맞게 잡았다. */ private calendarFor; private ensure; /** * **재개점** — 이 누적기의 상태 전부(이어 계산의 씨앗). * * ── 왜 필요한가 (2026-08-18) ──────────────────────────────────────────────── * 가동 이력은 원 시스템이 누적을 주지 않아 **우리가 이벤트를 적분해** 만든다. 그래서 저널을 꼬리만 * 계산하면 이 누적기는 꼬리분만 갖게 되고, 화면의 가용률·수율이 알리지 않고 작아진다(오류는 나지 않는다). * 재개점을 함께 저장·복원해야 「이어 계산한 값」이 「0부터 계산한 값」과 같아진다. */ serialize(): OeeCheckpoint; /** 재개점에서 되세운다 — 모르는 것은 지어내지 않는다(없으면 빈 누적기다). */ restore(cp: OeeCheckpoint | undefined | null): void; /** equipment.status(시간-in-상태) + quality.output(양품/불량) 소비. 다른 eventType 무시. */ apply(env: CanonicalEnvelope): void; /** 무버 OEE 카운터 — 마지막 상태 구간을 nowMs(기본=최신 이벤트 시각)까지 flush. busy→run 근사, setup=0. */ counters(moverId: string, nowMs?: number): OeeCounters; /** 공유 공식으로 근사 OEE 산출 — 정확한 OEE 는 실 텔레메트리(option ①). nowMs 기본=최신 이벤트 시각. */ oee(moverId: string, nowMs?: number): OeeMetrics; } /** * live State 를 OEE 로 보강 — projector 미러 State(관측)의 무버에 누적기 OEE(계산)를 채운다. * live-모드 publishEntityData 가 buildEntityDeltas 전에 적용 → equipment data(tag) payload 에 oee 포함 * (sim 은 커널이 채움 — 이로써 live 도 동일 payload 형상). 순수(입력 불변, 얕은 복사). */ export declare function withLiveOee(state: S, acc: OeeAccumulator, nowMs?: number): S; export {};