=== 민감단온도(T_C) 전환복귀제어 (작업플랜 구현) ===
- FeedforwardModels: TempLowLimit, TcReturnRebTarget/Band, TcReturnDeltaAdRef/Band 추가
- FeedforwardEngine: sigTLow (T_C 하한 트리거, -1e9=비활성) + 온도기반 복귀게이트(tcRecovered)
-> Recovering→Returning 전이: mbRecovered(물질수지) OR tcRecovered(reb-A+ΔT+T_C)
- FeedRampCalculator: 하강 램프 전면 구현 (RateUpPerMin/RateDnPerMin 분리, θ_up/θ_dn 분기, floor clamp)
- FeedRampExecutorService: 하강 램프 step 방향 지원
- FeedforwardConfigStore: 신규 6개 컬럼 SELECT/INSERT/UPDATE
- Hc900DbContext: temp_low_limit, tc_return_reb_target/band, tc_return_delta_ad_ref/band
- FeedforwardController: API 노출 + feed-ramp start/cancel/status
=== SteamAdvisor ===
- SteamAdvisorController: steam map 로드/시각화/제품매칭/온도프로파일
- steam.js, steam.html: SteamAdvisor 전용 UI 패널
=== Feed Ramp 실행 ===
- FeedRampExecutorService: BG service (BackgroundService)
- FeedRampJobStore: in-memory job store
- FfTrackingStore: ramp tracking DB
- FeedforwardSupervisor/WriteGuard: SP 쓰기 advisory + rate-limit
=== 분석 스크립트 ===
- gen_temp_profiles.py: 컬럼 온도 프로파일 기준 산출 → c{prefix}_tempref.json
- export_plotdata.py: analysis 결과 plot data export
- gen_instrument_ranges.py: 계기 범위 생성
- c6111_extract.py: C-6111 추출/운전모드 분류
- run_column.py: 전체 분석 파이프라인
=== Web UI ===
- ff.js/ff.html/ff.css: 전환류 상태기계 UI, TagBrowser, config save
- fast.js: Fast 조작 패널
- trend.js, pb.js, llmchat.js: 각 패널 확장
9.7 KiB
작업지시서 — operator-assist 웹 패키징 (2026-06-06)
전체설계
docs/학습형제어-오퍼레이터모방-플랜.md, 이전단계docs/작업지시서-학습형제어-다음단계.md. 메모리~/.claude/.../memory/learned-control-operator-imitation.md.
0. 컨텍스트 (필독)
- 오프라인 분석 완주: 7 train(6-1·6-2·8·9-1·9-2·10-1·10-2) prodmap·shadow·rolling·startup·shutdown 완료. 5차=운전부재 제외. 10차 둘=시운전 신뢰낮음.
- 선결 클린징 완료(2026-06-06):
gen_instrument_ranges.py→instrument_ranges.json(태그별 계기 EU range).c6111_extract.clip_to_ranges가 range밖 스파이크→NaN. 전 컬럼 envelope 정상화(9-2 feed 558332→453.6). 8차 부수개선 R²0.630→0.831. - range 소스 원칙: realtime_table
PV_HighRange/LowRange(실측, online 5·6·8차 권위) > xlsxInstructionsDisplayNumber(미연결 9·10차 fallback). ★C# 운영엔 xlsx 하드코딩 금지 — realtime live로 읽음. - (a)+(b) 통합 이유: 라이브 advisory 시각화는 (a)패키징과 (b)C#live가 한 덩어리. 분리하면 (a)는 그릴 라이브데이터 없고 (b)는 화면 없음.
- 차트 라이브러리 기보유:
echarts.min.js(trend.js 사용, 산점/막대/정렬),uPlot.iife.min.js(fast.js, 조밀 시계열 33만점). 신규 의존성 0.
목표
정적 png 분석을 라이브 advisory 웹 대시보드 + 백테스트 차트로. write 금지(advisory_only).
레이어 ① Python 좌표 JSON export [(b) 무관, 먼저 가능]
목적: png 만들던 분석이 좌표 배열 JSON도 동시 export → 웹이 그대로 렌더.
단계:
- 각 분석 스크립트(
c6111_prodmap/startup/operator_assist)에--json출력 추가, 또는 신규export_plotdata.py로 일괄. - 컬럼별
c{prefix}_plotdata.json산출:- prodmap: 운전점 산점(feed,steam_flow), valve곡선(op,flow_up/dn), pred-vs-actual, feature importance.
- startup: 컷인정렬 다중에피소드 시계열(rel분, reb/steam/reflux/feed), 컷인 트리거(reb-A 84.6±0.5, ΔT 1.9±0.4).
- shadow: advisory-vs-actual OP 다운샘플(LTTB or 6h), error 히스토그램 bins(서버집계).
- 33만행 원본 금지 — 반드시 서버 다운샘플.
검증: JSON으로 matplotlib png 재현 가능.
레이어 ② C# 백엔드 [(b) 본체]
현 상태: SteamAdvisor.cs Predict단건 + /api/steam/predict(수동입력)만. live연결·로깅·UI 전무.
단계:
- 라이브: 실시간 태그(feed FICQ-x101, product x118, T_C TI-x111C) 자동 read→
Predict→시계열 버퍼/FfTrackingStore로깅.GET /api/steam/live(현재 모드/권장OP/신뢰도/최근N분 추이). range=realtimePV_HighRange/LowRangelive. - 백테스트:
c{prefix}_plotdata.json서빙GET /api/steam/backtest/{col}. - 모드분류(PROD/STARTUP…) + OOD게이트 C#에 이미 포팅됨(envelope=데이터quantile, xlsx 아님).
검증: live 태그로 advisory 산출·로깅. OOD시 "범위밖→수동" 표시. write 0건.
주의: 6차만 online(C3). 9·10차(C4)는 데모 미연결 → 백테스트 차트만, 라이브 패널 6차 우선.
레이어 ③ 프론트 [②후]
단계:
wwwroot/js/steam.js+panes/steam.html, index.html 등록.- 라이브 패널(uPlot): 권장 vs 실제 OP 추이, 모드/신뢰도 배지, 권장OP 게이지.
- 백테스트 탭(ECharts): prodmap 산점, startup 정렬, shadow 시계열+히스토그램. 컬럼 선택.
- 호버 툴팁(feed/product/T_C/권장OP), 줌/팬.
검증: png 수준 그래픽 + 인터랙티브. 컬럼 전환 동작.
권장순서
①(Python export) → ②(C# live+백테스트 API) → ③(프론트). ①은 (b) 무관해 즉시 착수 가능.
검증기준 (전체)
- 라이브: 6차 advisory 표시·로깅, OOD폴백, write 0.
- 백테스트: 전 컬럼 차트 png 동급.
- first-cut 라이브 컬럼: 6-1차(shadow94%·advisory92.2% 최상, C3 online).
진단보고서 (diagnosis-checklist.md STEP 1-8 완료, 2026-06-06)
맥락 (STEP 1-2)
| 계층 | 진단 대상 | 상태 |
|---|---|---|
| ① Python export | export_plotdata.py 없음. 모든 분석 스크립트 PNG만 출력 |
미착수 |
| ② C# backend | SteamAdvisor.cs Predict+controller 있음. live/backtest API 없음 |
일부 완료 |
| ③ Frontend | steam.js/steam.html 없음, index.html 미등록 |
미착수 |
관련 문서: docs/학습형제어-오퍼레이터모방-플랜.md(설계), docs/작업지시서-학습형제어-다음단계.md(이전단계). 전 단계 작업4에서 SteamAdvisor.cs+컨트롤러까지 포팅 완료.
호출 계층 지도 (STEP 3-4)
# C# 현황
GET /api/steam/predict?feed=&product=&tC=
→ SteamAdvisorController.Predict()
→ SteamAdvisor.Predict()
→ ClassifyMode() (hardcoded thresholds)
→ InEnvelope() (envelope dict)
→ PolyVal() (3차 valve inverse)
→ return SteamAdvisoryResult
# Layer ② 구축 필요
Hc900RealtimeService (1s polling) → realtime_table (FICQ-x101/x118/TI-x111C)
→ 새로운 background service: live read → Predict → 버퍼/로깅
→ GET /api/steam/live (현재 advisory)
→ GET /api/steam/backtest/{col} (plotdata.json 서빙)
# Layer ③ 구축 필요
index.html → steam.js + steam.html
→ live 패널 (uPlot) : 권장OP vs 실제 OP 추이
→ backtest 탭 (ECharts) : prodmap/startup/shadow 차트
체크리스트 결과 (STEP 5-7)
🔴 HIGH (0건)
해당 없음 — 모든 작업은 신규 개발, 기존 운영코드 변경 없음.
🟠 MED (2건)
M1. Predict 파라미터 검증 없음
문제: SteamAdvisorController.Predict()에서 feed/product/tC에 [Required]·[Range] 미적용. 기본값 0이 그대로 전달되어 NaN이 아닌 0으로 예측 수행 → "정상"으로 오인 가능.
근거: SteamAdvisorController.cs:24-27 — [FromQuery] double feed에 검증 속성 없음.
영향: 잘못된 입력(0, 음수)이 조용히 Predict 통과 → 신뢰도 HIGH로 표시되어 오퍼레이터 혼동.
수정: [FromQuery][Required][Range(0,2000)] double feed 등 검증 추가, 실패 시 400 반환.
M2. ClassifyMode 임계값 컬럼 종속 — 다중 컬럼 대응 필요
문제: ClassifyMode(feed, product, tC)가 6-1차 하드코딩(product>100=PROD, feed>50=PROD, tC>60=LINEOUT). 8차(공급원 C4) 등 다른 컬럼은 product 스케일·feed 범위가 다름.
근거: SteamAdvisor.cs:121-127 — 임계값 상수. SteamModel.Column 속성은 존재하나 미사용.
영향: 8/9/10차 백테스트 차트에서 모드분류 오동작 → 잘못된 advisory 표시.
수정: SteamModel에 ModeThresholds { FeedProdMin, ProductProdMin, TcLineoutMin } 추가, ClassifyMode가 모델별 임계값 사용. 6-1 기본값 유지.
🟡 LOW (3건)
L1. 모델 경로 절대경로 하드코딩
문제: appsettings.json과 SteamAdvisor.cs 기본값 모두 /home/windpacer/projects/hc900_ax/... 절대경로. 배포 서버에서 동작 불가. 또한 단일 모델만 로드 — 백테스트 API에서 컬럼 전환 불가.
근거: appsettings.json:68, SteamAdvisor.cs:44.
영향: 배포 시 수동 경로 수정 필요. 백테스트는 별도 컬럼별 모델 로드 로직 추가 필요.
수정: (a) 상대경로 scripts/analysis/{column}_model.json 패턴 사용, (b) LoadModel(path)로 동적 로드 지원(이미 있음), (c) 백테스트용 GetModel(column) 추가.
L2. Python 스크립트 BASE 경로 하드코딩
문제: c6111_prodmap.py:20, c6111_operator_assist.py:14, c6111_shadow.py:15 등 모든 분석 스크립트가 BASE = "/home/windpacer/.../scripts/analysis/" 절대경로. --data 인자로 우회 가능하나 기본값이 깨짐.
근거: 각 스크립트의 BASE 상수.
영향: 다른 환경에서 --data 생략 시 FileNotFoundError. PNG 저장도 BASE 경로에 고정.
수정: os.path.dirname(os.path.abspath(__file__)) 기반 상대경로 또는 인자화.
L3. PredictAsync가 동기 래퍼
문제: PredictAsync()가 ValueTask.FromResult(Predict(...)) 반환 — 실제 비동기 동작 없음. CPU-bound이므로 sync가 적절하나 Async 접미사 오해 소지.
근거: SteamAdvisor.cs:115-119.
영향: 성능 영향 없음. 호출자 입장에서 async로 오인 가능.
수정: (현상 유지 권장) 주석 추가 또는 sync Predict() 직접 호출.
교차 검증 완료 (STEP 6)
| 항목 | Q1. 이미 수정? | Q2. 타 레이어 처리? | Q3. 의도적 설계? | Q4. 재현 시나리오? | 판정 |
|---|---|---|---|---|---|
| M1. 파라미터 검증 | 아니요 | SteamAdvisorController 자체에 없음 |
아니요 | feed=0 전송 시 0으로 예측 → HIGH 표시 | MED |
| M2. 모드 임계값 | 아니요 | SteamAdvisor 단독 |
6-1 pilot은 의도적 | 8차 백테스트에서 PROD 미인식 | MED |
| L1. 모델 경로 | 아니요 | IConfiguration 주입 |
아니요 | 백테스트 컬럼 전환 시 FileNotFound | LOW |
| L2. BASE 경로 | 아니요 | CLI 기본값 | 편의상 | --data 생략 시 오류 |
LOW |
| L3. PredictAsync | 해당 없음 | 해당 없음 | CPU-bound sync = 의도적 | 없음 | 제외(Q3) |
자가 검증 (STEP 8)
- 각 지적 사항을 현재 파일 몇 번 줄로 직접 가리킴
- HIGH 항목 없음 — 신규 개발이므로 기존 운영코드 변경 없음
- 교차 검증 4개 질문 모두 통과한 항목만 포함
- 수정 예시가 현재 코드에 아직 적용되지 않은 내용
- "더 좋은 방법 제안"과 "현재 코드가 틀렸다" 혼동하지 않음