고객 클레임이 하나 들어왔다. 3개월 전 출하분, 특정 chamber를 의심한다. MES에서 해당 기간 lot을 뽑아 보니 PROC_END event는 전부 있는데 그중 40여 건에 chamber id가 비어 있다. Host log를 뒤져 보면 S6F11은 다 받았고 S6F12로 ACKC6 = 0까지 정상으로 돌려줬다. 통신은 한 번도 안 끊겼다.
Event가 도착한 것과 이력이 남은 것은 다른 얘기다. 여기서 시간 제일 많이 버린다.
Event 자체가 스스로를 설명해야 한다
가장 흔한 설계 실수는 lot context를 event에서 빼는 것이다. "MES가 지금 뭐가 loaded인지 알고 있으니 CEID만 보내면 된다"는 논리다. 정상 흐름에서는 맞다.
깨지는 순간은 정해져 있다.
- Event가 spool에 갇혔다가 20분 뒤에 도착한다. MES의 "현재 lot"은 이미 다음 lot이다.
- Port 두 개짜리 설비에 carrier가 동시에 두 개 물려 있다. CEID 하나로는 어느 쪽인지 모른다.
- 정비 중에 사람이 lot을 손으로 옮겼고, MES dispatch state가 설비 실물과 다르다.
그래서 각 production event의 report에는 lot/unit id, equipment id와 chamber·lane·port 같은 세부 위치, route step, recipe id 와 recipe version, carrier id, 그 step에서 소비한 material lot이 함께 실려야 한다. 여기에 event quality 한 칸 — normal / manual / inferred / corrected / late / duplicate — 을 붙인다.
이건 MES가 검증을 안 해도 된다는 뜻이 아니다. 3개월 뒤에 그 event 한 줄만 보고도 무슨 일이 있었는지 알 수 있어야 한다는 뜻이다.
GEM 쪽이라면 이 목록이 그대로 RPTID 설계다. S2F33으로 report를 define하고 S2F35로 CEID에 link한다. 그 순서를 건너뛰면 CEID는 살아 있는데 report는 빈 채로 날아온다 — GEM 링크는 초록불인데 MES는 왜 run을 복원하지 못하나에 그 실패가 어떻게 생기는지 정리해 뒀다.
먼저 무엇을 추적할지 정한다
Site에서 "lot"이라고 부르는 대상이 무엇인지부터 합의해야 한다. 업종마다 다르고, 추적 단위는 barcode scan, PLC data block, MES table, operator screen에 전부 영향을 준다.
| 대상 | 예 | 주의할 점 |
|---|---|---|
| Lot 또는 batch | Chemical batch, food batch, pharma lot | 일정 시간 구간의 process condition이 중요 |
| Unit | Serial number, assembly id | 개별 pass/fail, rework 이력이 중요 |
| Carrier | Cassette, tray, pallet, rack | Carrier는 그대로인데 내용물이 바뀐다 |
| Panel 또는 strip | PCB panel, lead frame strip | Parent 하나가 나중에 여러 unit으로 갈라진다 |
| Roll 또는 coil | Film roll, steel coil, cable reel | 길이 위치까지 있어야 의미가 있다 |
| Container | Tote, tank, silo | 세척·blending 뒤 material identity가 바뀐다 |
설비가 LotStart만 보내는데 요구사항은 serial 단위 이력이라면, 배선을 시작하기 전에 모델이 이미 부족하다. 나중에 MES에서 만들어 낼 수 없다.
Event time과 receive time은 다른 값이다
Timestamp가 틀리면 공정 이력이 거짓말을 한다. NTP가 2분만 밀려도 lot이 dryer에 들어가기 전에 나온 것처럼 보인다.
최소한 두 개를 따로 저장한다. Event time은 설비에서 상태가 실제로 바뀐 시각, receive time은 MES가 저장한 시각. 평소엔 거의 같다. Network가 끊겼다 붙는 순간 수십 분씩 벌어지고, 그때가 바로 이 구분이 유일하게 쓸모 있는 순간이다.
GEM에서 event time은 공짜로 오지 않는다. Clock variable을 report에 넣어야 온다. 안 넣으면 S6F11에는 시각이 없고, MES에 남는 건 receive time뿐이다 — spool에서 한꺼번에 쏟아진 event 40건이 전부 같은 초에 일어난 것처럼 기록된다. 시각 포맷은 TIMEFORMAT ECV가 정한다. 16자리 YYYYMMDDhhmmsscc를 쓰는 쪽이 안전하다. 12자리 YYMMDDhhmmss는 세기 정보도, 초 미만도 없어서 같은 초에 들어온 start/complete의 순서를 못 가른다.
설비 시계는 host가 S2F31 Date and Time Set Request로 맞추고 설비가 S2F32에 TIACK으로 답한다. Hookup 때 한 번 맞추고 끝내면 안 된다. 몇 달 지나면 드리프트가 lot 순서를 뒤집는다. Drift 감시는 traceability commissioning 항목이다.
Snapshot tag는 이력이 아니다
CurrentLotId 같은 tag를 주기적으로 읽어서 이력을 만들려는 시도를 자주 본다. GEM이면 S1F3로 SVID를 polling하는 형태다. 화면 표시용으로는 괜찮다. 이력으로는 못 쓴다. Poll 주기보다 짧은 사건은 통째로 사라지고, 값이 두 번 바뀌면 중간 값은 아무 데도 안 남는다.
필요한 건 transition이다. Lot loaded / carrier docked, process started, recipe selected와 verified, material consumed, process completed, lot unloaded, 그리고 hold·abort·rework·skip·manual release. 마지막 다섯 개가 실제로 조사에서 필요한 것들인데 제일 자주 빠진다.
각 transition에는 sequence number를 붙인다. 재연결 후에 뭐가 빠졌고 뭐가 중복 replay됐는지 확인할 방법이 이것밖에 없다.
Genealogy는 구조로 저장한다
Material이 split·merge·transform되는 순간이 traceability의 본체다. Roll 하나를 여러 child roll로 slitting하고, ingredient lot 둘을 blending해 batch 하나를 만들고, PCB panel이 나중에 개별 board로 분리되고, cassette 25장 중 chamber에는 8장만 들어간다. Rework는 새 serial이 아니라 같은 unit의 revised state를 만든다.
이걸 비고란에 문장으로 적으면 3개월 뒤 클레임이 왔을 때 query가 안 된다. Consumed material, produced material, carrier membership, split quantity, merge quantity, effective time을 각각 컬럼으로 잡아야 한다. Supplier lot 하나가 의심될 때 영향받은 제품을 몇 초 안에 뽑아낼 수 있는지가 이 설계의 유일한 시험이다.
GEM300 설비라면 직접 만들 필요가 없는 부분이 많다. E87이 carrier state, E90이 substrate tracking, E40이 process job, E94가 control job을 정의하고 각각 전이 event가 표준으로 있다. Vendor가 compliance를 주장한다면 custom CEID를 새로 파기 전에 이쪽부터 매핑한다. 직접 만든 event가 software release마다 번호 바뀌는 쪽이다.
Spool replay는 순서를 지켜주지 않는다
Host가 끊긴 동안 설비가 event를 spool한다. 여기까지는 GEM이 해준다. MES가 잘못 기대하는 건 그다음이다.
Spool 대상은 host가 S2F43으로 허용한 stream/function만이다. Drain은 host가 S6F23을 보내야 시작되고, RSDC 값 하나가 transmit과 purge를 가른다. 그리고 drain 도중에도 설비는 실시간 event를 계속 만든다 — MES 입장에서는 20분 전 PROC_START와 방금 난 PROC_END가 몇 초 간격으로 섞여 들어온다. Event time 없이 receive time 순으로 정렬하면 이력이 뒤집힌다.
여기서 벌어지는 실패는 Host가 한 시간 끊겼을 때 SECS/GEM Spooling이 실제로 지켜주는 것에 따로 정리했다. MES 쪽 결론은 하나다. 정렬 키는 event time이고, receive time은 감사용으로만 남긴다.
Boundary에서 걸러내되, 버리지는 않는다
Integration layer는 명백히 이상한 event를 정상 이력으로 저장하면 안 된다. 필수 event에 lot id가 없거나, master에 없는 equipment·chamber·route step·recipe id가 오거나, timestamp가 미래이거나, 같은 event id에 payload가 다르거나, process start 없이 complete가 먼저 오는 경우다.
그런데 그냥 drop하면 안 된다. Raw payload와 reject 사유를 exception queue에 남긴다. 버린 event는 이력에서 그냥 없는 시간이 되고, 없는 시간은 아무도 못 찾는다. Reject 건수를 하루 단위로 볼 수 있는 화면 하나가 있으면 대부분의 조용한 붕괴를 초기에 잡는다.
Correction은 덮어쓰지 말고 쌓는다
Scan 누락, 늦게 온 tool event, restart 후 duplicate, 정비 중 수동 이동. 실제 라인은 이렇게 돌아간다. 입력이 완벽하다고 가정한 설계는 조용히 망가진다.
품질이나 고객 대응에 쓰는 record라면 append-only correction 말고 다른 선택지는 없다고 본다. 원 event를 그대로 두고 correction event를 추가한 뒤, report는 effective value를 보여주되 correction history를 열 수 있게 한다. Silent overwrite는 감사에서 방어가 안 된다.
정해 둬야 할 건 결국 권한 문제다. Lot id·time·route step·material consumption을 누가 고칠 수 있는가. Corrected record를 release 판단에 쓸 수 있는가. MES state와 설비 state가 다를 때 어느 쪽을 기준으로 라인을 막고, 누가 푸는가. 이걸 commissioning 때 안 정하면 사고 났을 때 정하게 된다.
Operator 화면에서 드러난다
Operator는 시스템이 지금 어떤 lot이 설비에 있다고 믿는지, 그리고 그 근거가 scan인지 PLC value인지 MES dispatch인지 볼 수 있어야 한다. Barcode scan과 PLC lot id와 MES dispatch가 서로 다를 때 그 불일치가 화면에 뜨는지가 핵심이다.
MES error만 띄우는 화면은 라인을 복구시키지 못한다. Unknown lot인지, wrong route인지, duplicate event인지, material 누락인지, 통신 끊김인지 갈라서 보여줘야 한다.
현장에서 반복되는 failure mode
이력은 큰 구조보다 작은 예외에서 깨진다.
- 설비가 unload 뒤에
ProcessComplete를 보낸다. Lot context는 이미 다음 lot으로 바뀌어 있다. - Carrier id는 맞는데 carrier 안의 slot map이 stale이다. Wafer 8장짜리 partial lot에서 바로 드러난다.
- Recipe name만 저장하고 version을 안 저장한다. 반년 뒤 "그때 그 recipe"를 재현할 수 없다.
- Manual rework가 route model 밖에서 제품을 옮긴다.
- Barcode에는 leading zero가 있는데 PLC가 정수로 저장해서 날려 먹는다.
0012345와12345가 다른 lot이 된다. - Historian에는 process value가, MES에는 lot record가 있는데 둘을 join할 공통 키가 없다.
- Report 안 VID 순서가 설비 software update로 한 칸 밀렸다. Host가 위치로 파싱하고 있었다면 모든 필드가 어긋난 채로 저장된다.
이 항목들은 commissioning 때 일부러 만들어 봐야 한다. 정상 lot 한 개가 통과했다고 검증된 게 아니다. Hold를 걸고, network를 뽑고, 같은 event를 두 번 보내고, 시계를 틀어 놓고 돌려 본다.
운영 전에 확인할 것
- 각 event에 lot context, equipment context, route step, event time, quality flag가 있다.
- Report에 clock variable이 들어 있다. Spool drain 때 event time이 실제로 살아 온다.
- Equipment·SCADA·MES 시계가 동기화되어 있고 drift를 감시한다.
- Start·complete·abort·hold·rework·manual release 경로를 전부 시험했다.
- Split·merge·consume·produce가 genealogy로 저장된다.
- Duplicate·late·missing·out-of-order event가 눈에 보이게 처리된다.
- Historian process data와 MES lot을 explicit key로 join할 수 있다.
- Correction history가 auditable하고 원 event를 지우지 않는다.
2번이 제일 자주 빠지고, 빠진 걸 알아채는 시점은 항상 클레임이 들어온 뒤다.
설비가 실제로 보내는 event를 미리 확인해 보려면 SECS/GEM Simulator에서 host 쪽 파싱을 붙여 놓고 시험해 볼 수 있다.