@operato/ops-contract
v0.9.41
Published
Operations domain contract — the standard vocabulary that producers and readers agree on (EPCIS 2.0/GS1, ISA-95, IEC 61850/ISO 50001). Types, guards, validation. No state, no engine.
Readme
@operato/ops-contract
운영 도메인의 계약 — 사실을 만드는 쪽과 읽는 쪽이 합의해야 하는 것.
EPCIS 2.0 · GS1 물품의 이동과 계보
ISA-95 자재 · 설비 · 사람 · 공정
IEC 61850 · ISO 50001 전기 계통과 성과지표무엇이 여기 있고 무엇이 없나
여기 있는 것은 타입 · 판별 함수 · 정합 검증 · 어휘 상수입니다. 인자만 보고 답합니다.
여기 없는 것은 정책과 엔진입니다. 그 사실로 무엇을 할지는 @operato/twin-kernel 이 정합니다.
제품 간 AI 분석 입력 — OperationalAttentionV1
OperationalAttentionV1은 Plant·WMS·YMS·EMS가 자신이 관측한 운영 주의 사실을 Twin 또는 AI 분석기에
보낼 때 쓰는 공통 봉투입니다. 국제 표준의 알람 포맷을 새로 만드는 것이 아닙니다. EPCIS/ISA-95 등의
원본 사실을 어떤 제품이, 어떤 근거로, 무엇을 분석 대상으로 열었거나 닫았는지 안전하게 전달하는
Operato의 제품 간 계약입니다.
import {
OPERATIONAL_ATTENTION_CONTRACT,
assertOperationalAttentionV1,
type OperationalAttentionV1
} from '@operato/ops-contract'
const attention: OperationalAttentionV1 = {
contract: OPERATIONAL_ATTENTION_CONTRACT,
domainId: 'factory-a',
attentionId: 'schedule-overdue:line-a:101',
dedupeKey: 'schedule-overdue:line-a:101',
kind: 'plant.schedule-overdue',
subjectLabel: 'Line A schedule 101',
transition: 'opened',
impact: 'high',
observedAt: '2026-09-12T01:00:00.000Z',
evidenceFingerprint: 'sha256:...',
facts: [{ system: 'operato-plant', type: 'schedule-entry', id: '101' }]
}
assertOperationalAttentionV1(attention)공통으로 고정한 것
- 식별·재전송:
attentionId,dedupeKey - 분석 수명주기:
opened,changed,resolved,reopened - 분석 우선순위:
medium,high - 근거: 최소 하나 이상의 안정된
{ system, type, id }원본 사실 참조와evidenceFingerprint
사람이 읽는 제목만 있고 원본 사실 ID가 없는 입력은 거부합니다. AI가 그럴듯한 설명을 만들더라도 근거를 다시 열어 볼 수 없으면 운영 분석의 입력이 될 수 없기 때문입니다.
제품별로 남기는 것
kind와 facts[].type은 생산자가 소유합니다. 예를 들어 Plant는 plant.schedule-overdue, WMS는
wms.short-pick을 쓰며 서로의 업무 모델을 흉내 내지 않습니다. 또한 acknowledged, suppressed,
승인, 실제 조치 결과는 생산 제품의 업무 흐름에 남습니다. 이 계약은 분석에 필요한 사실 변화만
전달하며, 수신자가 현장을 조치할 권한을 주지 않습니다.
새 제품이 붙을 때는 공통 봉투를 넓히기 전에 그 제품의 adapter에서 자기 kind·사실 유형·판정 기준을
검증합니다. 모든 제품이 실제로 공유하는 필드만 이 계약에 추가합니다.
기존 webhook을 통한 전송
새 URL은 만들지 않는다. attention도 기존 POST /domain/{domain}/twin/hook/{source}/{instanceId}로 보내며,
봉투의 lane: 'ATTENTIONS'가 Twin의 AI inbox 경로를 고른다. scope는 계속 원천의 순번 흐름 이름이며
lane과 합치지 않는다. lane을 생략한 기존 커넥터는 FACTS로 읽혀 기존 canonical ingest 경로를 그대로
쓴다. 따라서 주소·서명·재시도·순번 규약은 하나이고, 사실과 attention의 저장·처리만 Twin 내부에서 갈린다.
Webhook 봉투에서의 구분
lane은 전달 목적, scope는 생산자의 순번 스트림 이름이다. 같은 값으로 쓰거나 scope를
ATTENTIONS로 바꾸지 않는다.
const batch = {
lane: 'ATTENTIONS', // 없으면 FACTS: 기존 커넥터와 호환
scope: 'mes-line-a', // 이 생산자가 관리하는 순번 스트림
items: [{
eventId: 'outbox-1002',
seq: 1002,
record: attention
}]
}| lane | Twin 내부 목적지 | 정본 저널 반영 |
| --- | --- | --- |
| FACTS 또는 생략 | 기존 canonical ingest | 예. EPCIS/운영 사실로 유입한다. |
| ATTENTIONS | 제품이 등록한 AI attention inbox | 아니오. 분석을 요청하는 근거 묶음으로 분리한다. |
두 lane 모두 같은 webhook 인증·서명·순번·재시도 응답 계약을 쓴다. 수신자는 OperationalAttentionV1의
도메인 일치와 원본 사실 참조를 검증하고, 같은 domain/source/instance/attention/evidenceFingerprint는
중복으로 처리한다. 이 계약은 attention을 현장 명령으로 바꾸지 않는다.
왜 나뉘어 있나
사실을 만드는 쪽(MES · 커넥터)은 계약만 필요하고 엔진은 필요 없습니다. 한 패키지에 두면 레코드 하나를 만들려고 시뮬레이션 엔진과 네 도메인 커널을 의존 그래프에 올리게 됩니다.
타입만이면 import type 으로 피할 수 있지만, 판별 함수는 런타임 함수입니다(isEnergyRecord 계열).
보내는 쪽이 보내기 전에 스스로 검증하려면 실제로 필요합니다.
