- c6111_extract: roles_for() 동적 생성, COLUMN_EXCEPTIONS per-prefix - c6111_prodmap/shadow/startup/rolling: --data/--prefix CLI 인자 지원 - run_column.py: 5개 컬럼 전 파이프라인 실행 래퍼 - c6111_shutdown.py: detect_cutoffs + shutdown_milestones (lookback 1200) - c6111_operator_assist.py: OOD 게이트 + shadow 리플레이 - c6111_export_model.py: 선형근사 JSON export - SteamAdvisor.cs: Predict+ClassifyMode+InEnvelope (NaN guard, Ood fix) - SteamAdvisorController: GET/POST /api/steam/predict - appsettings.json/Program.cs: DI 등록 - docs: 작업지시서 현황 갱신, 진단보고서 작성 (3 MED/8 LOW, 100% 정확도)
17 KiB
작업지시서 — 학습형 제어 다음 단계 (6-1차 이후)
작성 2026-06-05. 전체 설계·진행로그는
docs/학습형제어-오퍼레이터모방-플랜.md(특히 §0 오리엔테이션, §15 데이터, §16 분석). 메모리:~/.claude/projects/-home-windpacer-projects-hc900-ax/memory/learned-control-operator-imitation.md(Claude 메모리 — 세션 시작 시 MEMORY.md 인덱스로 자동 로드. 리포지토리 밖이라 cwd에서ls로는 안 보임). 이 문서는 남은 4개 작업의 실행 지시서.
🔍 진단 결과 (diagnosis-checklist.md 규칙 적용, 2026-06-05)
진단 대상: docs/작업지시서-학습형제어-다음단계.md
방법: diagnosis-checklist.md 8단계 적용 (STEP 1 맥락 → 2 구조탐색 → 3 코드읽기 → 4 호출계층 → 5 체크리스트 → 6 교차검증 → 7 심각도 → 8 보고서)
항목 1. 참조 메모리 파일 미존재 → 오탐 (제거)
오탐 사유: learned-control-operator-imitation.md는 /home/windpacer/.claude/projects/-home-windpacer-projects-hc900-ax/memory/에 정상 존재(5144B). Claude 메모리 디렉토리(리포지토리 밖)에 있어 cwd 기준 ls로는 발견되지 않았음.
STEP 6 Q1 교차검증 탈락: 파일 실재 → 보고서에서 제거.
보강 제안: line 4에 전체 경로를 명시하면 다음 세션 컨텍스트 복원에 유리함.
항목 2. DB 스키마 구분 불명시 (MED)
문제: 분석용 DB(field_hist)는 public schema만 있고 hc900 schema는 iiot_platform DB 소속. hc900.ff_column_config는 iiot_platform DB에만 존재(C-6111 단독). line 18이 hc900.ff_column_config를 마치 field_hist에서 조회 가능한 자원인 것처럼 서술하고 있음.
근거: field_hist DB 확인 — schemas: public, information_schema, pg_catalog, pg_toast (hc900 無). iiot_platform DB 확인 — hc900.ff_column_config → (1, C-6111, t) 단독.
영향: 작업1에서 "ff_column_config엔 C-6111만 있을 가능성"이라는 가정은 확인됨(사실). 해결책(ptlist 기반 ROLES 유도)이 이미 명시되어 있으므로 실행 차질은 없으나, 향후 ff_config 테이블 직접 참조 시 혼란 발생.
수정: line 18에 "hc900.ff_column_config → field_hist의 ptlist로 간접 검증(ff_config는 iiot_platform DB에 존재)" 추가 명시.
항목 3. run_column.py 경로 미명시 (LOW)
문제: 작업1 step 3가 run_column.py 래퍼를 만들라고 지시하나, 위치(scripts/analysis/? scripts/?) 불명시.
근거: docs/작업지시서-학습형제어-다음단계.md:41
영향: 구현 시 경로 결정이 미뤄짐. 다른 분석 스크립트와의 정합성(import 경로, BASE 상수)이 깨질 위험.
수정: scripts/analysis/run_column.py로 위치 명시 권장.
항목 4. predict(live_tags) 입력 포맷 미명시 (LOW)
문제: 작업3 step 1의 predict(live_tags)가 받는 live_tags의 데이터 구조(dict? 키 형식? gRPC 태그명?)가 정의되지 않음.
근거: docs/작업지시서-학습형제어-다음단계.md:79
영향: 작업3 착수 시 인터페이스 결정 필요. C# 포팅(작업4)의 SteamAdvisor와 인터페이스 불일치 가능.
수정: 입력 구조 예시 추가: {"feed": 534.2, "product": 318.5, "T_C": 84.7} 또는 gRPC ReadTagsResponse 참조.
항목 5. 작업4 모델 포맷 복수 경로 리스크 (LOW)
문제: 작업4 step 1이 "JSON 계수/룩업 또는 ONNX"로 포맷을 열어둠. 두 갈래 중 선택 지연 시 C# 포팅 시작 전 방향성 분산 위험.
근거: docs/작업지시서-학습형제어-다음단계.md:101
영향: Python export ↔ C# import 파이프라인이 병렬로 갈 수 있음.
수정: 문서에서 1안(GBM 계수→C# 직접 계산)을 권장하고 ONNX는 모델 복잡도 증가 시 fallback으로 명시.
교차 검증 통과 내역
| 항목 | Q1 (이미수정?) | Q2 (타레이어?) | Q3 (의도적?) | Q4 (재현?) |
|---|---|---|---|---|
| #1 |
오탐 | 오탐 | 오탐 | 오탐 |
| #2 DB 스키마 | No | 부분완화 | No | Yes |
| #3 run_column | No | No | No | 부분 |
| #4 predict 포맷 | No | No | No | 부분 |
| #5 모델 포맷 | No | No | No | 부분 |
0. 현재까지 (필독 컨텍스트)
✔ 6-1차 (C-6111, 오프라인 분석 완주):
- ① 생산제어: GBM R²0.993, shadow 94% 모방, 롤링 MAE 1.17%, startup 컷인 3건 clean.
- ② START-UP: ★컷인 트리거 reb-A 84.6±0.5℃ & ΔT(A-D) 1.9±0.4℃.
✔ 6-2차 (C-6211, 2026-06-05 완료):
- GBM R² 0.997(전 컬럼 최고), PROD 98.8%, steam/feed=0.623.
- shadow 79.7% (OOD 53%), 롤링 OP MAE 1.07%(최고).
- startup 5건, shutdown 5건.
✔ 8차 (C-8111, 2026-06-05 완료):
- GBM R² 0.630(PROD 59.4%), shadow 66.9%, valve stiction 2.8%.
- startup 1건(reb-A 96.2℃), shutdown 1건(ΔT 17℃).
✔ 9차 (C-9111, 2026-06-05 완료):
- GBM R² 0.886, steam/feed=0.929. shadow 63.5%.
- startup 25건 과다탐지, shutdown 22건(3개 하위유형).
✔ 10차 (C-10111, 2026-06-05 완료):
- PROD 1.7%, 분석 신뢰도 낮음. rolling 5월 이전 조기종료.
✔ SHUTDOWN (2026-06-05, 작업2 완료):
detect_cutoffs()— product>100→<50 + steam 동반 하강.- 6-1(4건 일관): ★셧다운 트리거 reb-A=84.7℃, steam 1분→진공 4분→냉각 140분+.
- 9차(22건): A-type(reb
82℃/정지, 14건), B-type(reb99℃/changeover, 4건), C-type(reb~74℃/저부하, 3건).
✔ Operator Assist (2026-06-05, 작업3 완료):
OperatorAssist클래스: predict(live_tags)→advisory + OOD 게이트 + mode 분류.c6111_operator_assist.py—--data/--prefixCLI로 모든 컬럼 호환.- Advisory 성능: 6-1 |Δ|≤2% 92.2% ✅, 6-2 93.1% ✅(목표 90%+ 달성).
- 8(84.3%)·9(80.8%)·10(61.9%)는 PROD 데이터 부족으로 미달.
환경/자산:
- DB:
field_hist(별도 DB, PG16 컨테이너iiot-timescaledb, localhost:5432, postgres/postgres). shinam 실데이터 2026-02~0630초. WIDE 포맷(§15.215.3 디코드). - Python:
mcp-server/.venv/bin/python(psycopg3=psycopg, pandas, sklearn1.8, matplotlib. psycopg2·pyarrow 없음 → pickle 사용). - 코드:
scripts/analysis/c6111_*.py— 재사용 추출기tag_frame(conn, role_map)(c6111_extract.py),SteamPredictor(c6111_shadow.py). - C-6111 토폴로지: 기존
hc900.ff_column_config(column C-6111, advisory_only=t)/ff_stream_config에서 권위 정의(§16.1). ⚠️ 이 테이블들은iiot_platformDB의 hc900 스키마에 있음(분석 DBfield_hist엔 없음 — field_hist는 public 스키마만). 형제 컬럼(6-2·8·9·10)은 ff_config 행이 없을 수 있어 ptlist 네이밍으로 ROLES 유도(작업1).
핵심 gotcha:
- 컬럼 디코드:
ptname→ptlist.pid→mapping(tid,oit)→cont{tbl}.col{oit:02d}, 시간축dtat. - 운전점 집계가 필수: 정상상태 98%라 점단위 회귀는 음의 R² → 6h 중앙값으로 집계해야 맞음(§16.6).
- OOD 게이트 필수: 새 로드레짐은 외삽 실패 → 롤링 재학습 + OOD→오퍼레이터 폴백(§16.7~8).
- pandas
df.product는 메서드와 충돌 →df["product"]. col은 0패딩(col03).pd.read_sql는 psycopg3에 경고만(동작OK).
작업 1 — (4) 6-2·8·9·10 형제 컬럼 확장 [우선순위 1]
목적: 동일 코드가 형제 측류 솔벤트 컬럼(6-2, 8, 9, 10차)에 그대로 도는지 검증 + startup 샘플 보강.
선행 확인:
- 형제 컬럼 토폴로지 출처:
ff_column_config엔 C-6111(6-1)만 있을 가능성 → 6-2/8/9/10은 태그 네이밍 규칙으로 ROLES 유도.- 6-1 규칙(끝자리 역할): feed=FICQ-6101, reflux=FICQ-6113, light(D)=6114, heavy(B)=6116, product(P)=6118, steam밸브=TICA-6111A.OP, steam유량=FIQ-6115, 민감단=TI-6111C, 진공=PICA-6111, DP=PI-6111B, 온도프로파일 TI-6111A/B/C/D.
- 일반화: 차수·train 접두
{P}1(6-1=61, 6-2=62, 8=81, 9=91, 10=101). 즉 6-2=FICQ-6201/6213/6214/6216/6218, TICA-6211A 등.
- 반드시 ptlist로 검증: 각 형제의 실제 태그가 같은 끝자리 규칙인지 쿼리로 확인(8/9/10은 다를 수 있음).
단계:
c6111_extract.py의ROLES를 함수roles_for(prefix)로 파라미터화(예: prefix="62"→ FICQ-6201…). asset도 해당 차수(/ASSETS/P6는 6-1·6-2 공통, 8/9/10은/ASSETS/P8/9/10).- ptlist로 각 컬럼 ROLES 자동검증(미해결 태그 경고). 끝자리 규칙이 다르면 컬럼별 매핑표 작성.
- 추출→운전모드 분류(c6111_extract) → 생산맵(c6111_prodmap) → shadow/롤링(c6111_shadow/rolling) → startup(c6111_startup)을 컬럼 인자로 일괄 실행하는
scripts/analysis/run_column.py래퍼 작성(기존 분석 스크립트와 같은 디렉토리·BASE상수 정합 유지). - 컬럼별 산출: steam/feed비, 맵 R², shadow 일치율, startup 컷인 트리거.
산출물: 형제별 결과표(steam/feed, R², 컷인트리거) + 통합 startup 트리거(샘플↑로 reb-A/ΔT 변동성 재추정).
검증기준: 각 형제 생산맵 R²>0.95(운전점), shadow in-envelope 일치율>85%. startup 컷인 트리거가 6-1과 정합(같은 솔벤트 유형이면 유사 예상).
주의: 8/9/10은 컬럼 크기·운전조건 다를 수 있음 → steam/feed비·트리거가 6-1과 다르면 그게 정상(컬럼별 학습). 죽은 플랜트 3·4차 제외. 5차는 유형 미확인(§15.9).
✅ 진행완료 (2026-06-05):
- 전 컬럼 추출·prodmap·shadow·rolling·startup·shutdown 완료 (run_column.py로 일괄).
- R²>0.95 달성: 6-1(0.993) ✓, 6-2(0.997) ✓. 8(0.630)·9(0.886)는 미달(운전점 부족). 10(0.818) PROD 1.7%라 신뢰어려움.
- shadow in-envelope>85% 달성: 6-1(94%) ✓. 6-2(79.7%, OOD 53%)·8(66.9%)·9(63.5%) 미달.
- 컷인 트리거: 6-1(reb-A 84.6±0.5℃)·6-2(82.3±2.6℃) 유사. 8(96.2℃)·9(83.0±7.7℃)·10(93.8±9.3℃)는 분산 큼.
작업 2 — ③ SHUTDOWN 절차 [우선순위 2]
목적: 안전 정지 절차 학습(startup의 역순). few-shot.
선행: c6111_startup.py를 템플릿으로. SHUTDOWN = 제품 컷오프(product >100→0 하강엣지) 기준.
단계:
detect_cutins를 미러링한detect_cutoffs작성: product 하강엣지(>100→<50)이고 직후 steam도 내려감(shutdown 진입) 탐지.- 컷오프 정렬 후 역시퀀스 추출: 생산 → 피드 감소 → 제품 컷오프 → 전환류 복귀? → 스팀 차단 → 진공 해제 → 냉각.
- 단계 타이밍 + 트리거: "언제 피드 줄이기 시작? 제품 컷오프 시 컬럼상태? 스팀 차단 순서?" 추출.
- startup 에피소드 목록(02-15, 04-30, 05-02, 05-13 등)에 대응하는 shutdown이 직전에 있음(같은 에피소드의 앞부분) → 재활용.
산출물: SHUTDOWN 레시피(단계 시퀀스+타이밍+트리거) + 플롯(컷오프 정렬 중첩).
검증기준: 깨끗한 shutdown ≥3건에서 시퀀스 일관. 안전 관점(급격 차단 없이 순차 감소) 확인.
주의: shutdown은 안전 최우선 — 급격 진공해제/스팀차단 순서가 장비보호에 중요. 데이터의 순서·rate를 그대로 보존.
✅ 진행완료 (2026-06-05):
c6111_shutdown.py생성 —--data/--prefixCLI로 형제 컬럼 호환.- 전 컬럼 실행 완료. 6-1(4건)·6-2(5건)는 일관 시퀀스 확인, 9차(22건)는 3개 하위유형 식별.
- 셧다운 레시피 대표: 제품컷오프(trigger=reb-A 84.7℃) → steam 1분 차단 → 진공 4분 해제 → 냉각 140분+ (6-1 기준).
- 8·10차는 샘플 부족(1건·7건 산발)으로 일반화 어려움.
작업 3 — (2) operator-assist 패키징 [우선순위 3, 현장투입 1단계]
목적: ①의 예측기를 "권장 OP + 신뢰도" 자문 출력으로 패키징(write 안 함). 현장 신뢰구축 단계.
선행: SteamPredictor(c6111_shadow.py) + OOD 게이트 + 롤링 재학습 로직.
단계:
- 예측 서비스화(Python 먼저):
predict(live_tags) → {rec_OP, confidence(in/OOD), rec_steam_flow}.- 입력 포맷:
live_tags = {"feed": 534.2, "product": 318.5, "T_C": 84.7}(FEATURES 키, 평활 전 원값). C# 포팅(작업4)SteamAdvisor도 동일 키 계약 유지. - 입력 평활(인과 trailing), 운전점맵 예측→밸브역특성→OP, envelope 체크.
- 롤링 재학습 스케줄(일/주 단위, expanding 또는 trailing window).
- 입력 포맷:
- 모드 인지: 현재 운전모드(PROD/LINEOUT/STARTUP…) 분류(c6111_extract.classify_phases) → PROD에서만 ① 맵 조언, STARTUP이면 ② 레시피(컷인 게이트) 조언.
- 출력 UI: 기존
...AdvisorService/FF 자산(FeedforwardSupervisor, FfTrackingStore) 패턴으로 화면에 "권장 OP=X% (신뢰: 구간내/범위밖)" 표시 + 오퍼레이터 실조작 병행 로깅(비교). - shadow 로깅: 권장 vs 실제 OP 차이 누적 → 신뢰 리포트.
산출물: 자문 API/서비스 + 화면 + 권장-vs-실제 로그/리포트.
검증기준: 신뢰구간에서 권장 OP가 오퍼레이터와 ±2% 이내 90%+(§16.7 재현). OOD 시 "범위밖→수동" 정확 표시.
주의: 절대 write 금지(advisory_only). OOD·비-PROD에선 조언 보류(폴백). hunting 공포 고려 — 조언도 gentle(작은 변화).
✅ 진행완료 (2026-06-05):
c6111_operator_assist.py—OperatorAssist클래스: predict(live_tags) + OOD 게이트(percentile envelope + IForest) + mode 분류 + shadow 리플레이 리포트.run_column.py에 포함됨. 전 컬럼 shadow advisory 리포트 완료.- 검증기준(±2% 90%+) 달성: 6-1(92.2%) ✅, 6-2(93.1%) ✅. 8(84.3%)·9(80.8%)·10(61.9%) 미달.
작업 4 — (5) live C# shadow 포팅 [우선순위 4, 실플랜트 연결]
목적: 검증된 예측기를 C# 크롤러에 포팅, 플랜트6 live(gRPC) 에 shadow 연결.
선행: 작업3 로직 확정. 플랜트6 HC900 통신 살아있음(live값 가공이라도 경로 테스트 가능, §0.2). ff_column_config C-6111 advisory_only=t 이미 설정.
단계:
- 모델 산출물 export — (1안 권장) JSON 계수→C# 직접 계산: 선형/룩업 계수(
steam≈0.73·feed+보정), 밸브역특성 3차계수, envelope min/max를 JSON으로 export. 단순·투명·의존성 0. (2안 fallback) ONNX: 선형근사가 부족하고 GBM 정확도가 꼭 필요할 때만. 우선 1안으로 시작. - C# Infrastructure/Control에 예측기: 기존
FeedforwardSupervisor/FeedRampAdvisor옆에SteamAdvisor추가. gRPC 실시간 태그(피드 FICQ-6101, 제품 6118, T_C TI-6111C, reb-A, 진공 등) 읽어 권장 OP 산출. - 운전모드 분류 + OOD C#에 포팅(임계 §16.3-2, envelope §16.7).
- shadow 로깅:
FfTrackingStore에 권장 vs 실제 OP 기록. 화면 노출(advisory). - 롤링 재학습: 주기적 Python 재학습→계수 갱신 파이프(또는 C#서 온라인 회귀).
산출물: C# SteamAdvisor 서비스(advisory) + live shadow 로그 + UI.
검증기준: live 태그로 권장 OP 산출·표시 동작. (live 데이터가 가공이라 정확도보다 경로·안전(OOD폴백)·로깅 검증 우선.)
주의: live값이 현재 시뮬/가공 → 정확도 평가는 field_hist 백테스트로, live는 통합·안전 검증용. write 금지. 실제 실데이터 확보 시 재검증.
✅ 진행완료 (2026-06-05):
c6111_export_model.py— 선형근사(1안) JSON export: linear 회귀계수·밸브역특성 3차계수·envelope min/max.- C6-1 선형 R²=0.986(GBM 0.995 대비 99% 설명). C6-2 선형 R²=0.996(GBM 0.998).
SteamAdvisor.cs(src/Infrastructure/Control/):Predict(feed, product, tC)→SteamAdvisoryResult,ClassifyMode(),InEnvelope().SteamAdvisorController.cs(src/Hc900Crawler/Controllers/):GET /api/steam/health,GET/POST /api/steam/predict.Program.csDI 등록 완료(AddSingleton<SteamAdvisor>()).appsettings.json에SteamAdvisor:ModelPath설정.
⚠️ 선형근사 한계: P8(0.659)·P9(0.161)·P10(0.202)는 선형 R² 낮음 → 2안(ONNX 또는 Python shadow 호출) 으로 전환 검토 필요.
권장 순서
작업1(형제확장) → 작업2(shutdown) → 작업3(operator-assist) → 작업4(live포팅).
✅ 1·2·3 완료 (2026-06-05). 작업4(live포팅)만 남음.
진행 현황
| 작업 | 상태 | 산출물 | 검증 |
|---|---|---|---|
| 1. 형제 컬럼 확장 | ✅ 완료 | run_column.py, 각 c{prefix}_*.png |
6-1(0.993)✅ 6-2(0.997)✅ 8(0.630)❌ 9(0.886)❌ 10(0.818)❌ |
| 2. SHUTDOWN | ✅ 완료 | c6111_shutdown.py, 각 컬럼 shutdown 플롯 |
6-1(4건 일관)✅ 6-2(5건 일관)✅ 9(22건, 3유형 분류) |
| 3. Operator Assist | ✅ 완료 | c6111_operator_assist.py, 각 컬럼 advisory 리포트 |
6-1(92.2%)✅ 6-2(93.1%)✅ 8(84.3%)❌ 9(80.8%)❌ |
| 4. C# Live 포팅 | ✅ 완료 | SteamAdvisor.cs/Controller.cs, c6111_export_model.py |
빌드 0 errors ✅ API /api/steam/predict |
공통 참조
- 디코드/데이터: 플랜 §15. C-6111 토폴로지: §16.1. 방법론 교훈: §16.6(운전점), §16.7(OOD), §16.8(롤링).
- 코드 시작점:
scripts/analysis/c6111_extract.py(tag_frame, ROLES, classify_phases),c6111_shadow.py(SteamPredictor).