# 작업지시서 — 학습형 제어 다음 단계 (6-1차 이후)

> 작성 2026-06-05. 전체 설계·진행로그는 `docs/학습형제어-오퍼레이터모방-플랜.md`(특히 §0 오리엔테이션, §15 데이터, §16 분석).
> 메모리: `learned-control-operator-imitation.md`. 이 문서는 **남은 4개 작업의 실행 지시서**.

---

## 0. 현재까지 (필독 컨텍스트)

**완료(6-1차 컬럼 C-6111, 오프라인 분석 완주):**
- ① 생산제어: 전향맵 `스팀유량=f(피드,제품,목표T_C)` GBM R²0.99 (본질 steam/feed≈0.73) + shadow 94% 모방 + 롤링/OOD 안전 + 캠페인내 피드백 트림은 미미(컬럼 자기제어).
- ② START-UP: 레시피(진공→스팀승온→전환류 라인아웃→제품컷인→피드램프) + ★컷인 트리거 reb-A 84.6±0.5℃ & ΔT(A-D) 1.9±0.4℃(조건기반).

**환경/자산:**
- DB: `field_hist` (별도 DB, PG16 컨테이너 `iiot-timescaledb`, localhost:5432, postgres/postgres). shinam 실데이터 2026-02~06 ~30초. WIDE 포맷(§15.2~15.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).

**핵심 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 샘플 보강.

**선행 확인**:
1. 형제 컬럼 토폴로지 출처: `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-6111**C**, 진공=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 등.
2. **반드시 ptlist로 검증**: 각 형제의 실제 태그가 같은 끝자리 규칙인지 쿼리로 확인(8/9/10은 다를 수 있음).

**단계**:
1. `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`).
2. ptlist로 각 컬럼 ROLES 자동검증(미해결 태그 경고). 끝자리 규칙이 다르면 컬럼별 매핑표 작성.
3. 추출→운전모드 분류(c6111_extract) → 생산맵(c6111_prodmap) → shadow/롤링(c6111_shadow/rolling) → startup(c6111_startup)을 **컬럼 인자로** 일괄 실행하는 `run_column.py` 래퍼 작성.
4. 컬럼별 산출: 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).

---

## 작업 2 — ③ SHUTDOWN 절차  [우선순위 2]

**목적**: 안전 정지 절차 학습(startup의 역순). few-shot.

**선행**: `c6111_startup.py`를 템플릿으로. SHUTDOWN = **제품 컷오프(product >100→0 하강엣지)** 기준.

**단계**:
1. `detect_cutins`를 미러링한 `detect_cutoffs` 작성: product 하강엣지(>100→<50)이고 직후 steam도 내려감(shutdown 진입) 탐지.
2. 컷오프 정렬 후 역시퀀스 추출: 생산 → **피드 감소** → **제품 컷오프** → 전환류 복귀? → **스팀 차단** → **진공 해제** → 냉각.
3. 단계 타이밍 + 트리거: "언제 피드 줄이기 시작? 제품 컷오프 시 컬럼상태? 스팀 차단 순서?" 추출.
4. startup 에피소드 목록(02-15, 04-30, 05-02, 05-13 등)에 대응하는 shutdown이 직전에 있음(같은 에피소드의 앞부분) → 재활용.

**산출물**: SHUTDOWN 레시피(단계 시퀀스+타이밍+트리거) + 플롯(컷오프 정렬 중첩).

**검증기준**: 깨끗한 shutdown ≥3건에서 시퀀스 일관. 안전 관점(급격 차단 없이 순차 감소) 확인.

**주의**: shutdown은 안전 최우선 — 급격 진공해제/스팀차단 순서가 장비보호에 중요. 데이터의 순서·rate를 그대로 보존.

---

## 작업 3 — (2) operator-assist 패키징  [우선순위 3, 현장투입 1단계]

**목적**: ①의 예측기를 **"권장 OP + 신뢰도" 자문 출력**으로 패키징(write 안 함). 현장 신뢰구축 단계.

**선행**: `SteamPredictor`(c6111_shadow.py) + OOD 게이트 + 롤링 재학습 로직.

**단계**:
1. **예측 서비스화**(Python 먼저): `predict(live_tags) → {rec_OP, confidence(in/OOD), rec_steam_flow}`.
   - 입력 평활(인과 trailing), 운전점맵 예측→밸브역특성→OP, envelope 체크.
   - 롤링 재학습 스케줄(일/주 단위, expanding 또는 trailing window).
2. **모드 인지**: 현재 운전모드(PROD/LINEOUT/STARTUP…) 분류(c6111_extract.classify_phases) → PROD에서만 ① 맵 조언, STARTUP이면 ② 레시피(컷인 게이트) 조언.
3. **출력 UI**: 기존 `...AdvisorService`/FF 자산(FeedforwardSupervisor, FfTrackingStore) 패턴으로 화면에 "권장 OP=X% (신뢰: 구간내/범위밖)" 표시 + 오퍼레이터 실조작 병행 로깅(비교).
4. shadow 로깅: 권장 vs 실제 OP 차이 누적 → 신뢰 리포트.

**산출물**: 자문 API/서비스 + 화면 + 권장-vs-실제 로그/리포트.

**검증기준**: 신뢰구간에서 권장 OP가 오퍼레이터와 ±2% 이내 90%+(§16.7 재현). OOD 시 "범위밖→수동" 정확 표시.

**주의**: **절대 write 금지**(advisory_only). OOD·비-PROD에선 조언 보류(폴백). hunting 공포 고려 — 조언도 gentle(작은 변화).

---

## 작업 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 이미 설정.

**단계**:
1. **모델 산출물 export**: Python에서 학습한 steam맵(GBM)·밸브역특성·envelope를 경량 포맷(JSON 계수/룩업 또는 ONNX)으로 export. (선형근사 `steam≈0.73·feed+보정`이면 C#에서 직접 계산 가능 — 단순화 권장.)
2. **C# Infrastructure/Control에 예측기**: 기존 `FeedforwardSupervisor`/`FeedRampAdvisor` 옆에 `SteamAdvisor` 추가. gRPC 실시간 태그(피드 FICQ-6101, 제품 6118, T_C TI-6111C, reb-A, 진공 등) 읽어 권장 OP 산출.
3. **운전모드 분류 + OOD** C#에 포팅(임계 §16.3-2, envelope §16.7).
4. shadow 로깅: `FfTrackingStore`에 권장 vs 실제 OP 기록. 화면 노출(advisory).
5. 롤링 재학습: 주기적 Python 재학습→계수 갱신 파이프(또는 C#서 온라인 회귀).

**산출물**: C# `SteamAdvisor` 서비스(advisory) + live shadow 로그 + UI.

**검증기준**: live 태그로 권장 OP 산출·표시 동작. (live 데이터가 가공이라 정확도보다 **경로·안전(OOD폴백)·로깅** 검증 우선.)

**주의**: live값이 현재 시뮬/가공 → 정확도 평가는 field_hist 백테스트로, live는 통합·안전 검증용. write 금지. 실제 실데이터 확보 시 재검증.

---

## 권장 순서
**작업1(형제확장) → 작업2(shutdown) → 작업3(operator-assist) → 작업4(live포팅)**.
1·2는 분석 연장(코드 재사용·샘플보강), 3·4는 현장 투입. 3 전에 1로 다컬럼 일반화를 끝내면 assist가 전 컬럼 커버.

## 공통 참조
- 디코드/데이터: 플랜 §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).
