Files
HC900-Crawler/docs/작업지시서-operator-assist-웹패키징.md
windpacer 7b21c35af6 feat: 민감단온도 전환복귀제어 + SteamAdvisor + FeedRamp 전면 구현
=== 민감단온도(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: 각 패널 확장
2026-06-06 18:33:56 +09:00

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.pyinstrument_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차 권위) > xlsx InstructionsDisplayNumber(미연결 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 → 웹이 그대로 렌더.

단계:

  1. 각 분석 스크립트(c6111_prodmap/startup/operator_assist)에 --json 출력 추가, 또는 신규 export_plotdata.py로 일괄.
  2. 컬럼별 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(서버집계).
  3. 33만행 원본 금지 — 반드시 서버 다운샘플.

검증: JSON으로 matplotlib png 재현 가능.


레이어 ② C# 백엔드 [(b) 본체]

현 상태: SteamAdvisor.cs Predict단건 + /api/steam/predict(수동입력)만. live연결·로깅·UI 전무.

단계:

  1. 라이브: 실시간 태그(feed FICQ-x101, product x118, T_C TI-x111C) 자동 read→Predict→시계열 버퍼/FfTrackingStore 로깅. GET /api/steam/live(현재 모드/권장OP/신뢰도/최근N분 추이). range=realtime PV_HighRange/LowRange live.
  2. 백테스트: c{prefix}_plotdata.json 서빙 GET /api/steam/backtest/{col}.
  3. 모드분류(PROD/STARTUP…) + OOD게이트 C#에 이미 포팅됨(envelope=데이터quantile, xlsx 아님).

검증: live 태그로 advisory 산출·로깅. OOD시 "범위밖→수동" 표시. write 0건.

주의: 6차만 online(C3). 9·10차(C4)는 데모 미연결 → 백테스트 차트만, 라이브 패널 6차 우선.


레이어 ③ 프론트 [②후]

단계:

  1. wwwroot/js/steam.js + panes/steam.html, index.html 등록.
  2. 라이브 패널(uPlot): 권장 vs 실제 OP 추이, 모드/신뢰도 배지, 권장OP 게이지.
  3. 백테스트 탭(ECharts): prodmap 산점, startup 정렬, shadow 시계열+히스토그램. 컬럼 선택.
  4. 호버 툴팁(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 표시. 수정: SteamModelModeThresholds { FeedProdMin, ProductProdMin, TcLineoutMin } 추가, ClassifyMode가 모델별 임계값 사용. 6-1 기본값 유지.

🟡 LOW (3건)

L1. 모델 경로 절대경로 하드코딩

문제: appsettings.jsonSteamAdvisor.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개 질문 모두 통과한 항목만 포함
  • 수정 예시가 현재 코드에 아직 적용되지 않은 내용
  • "더 좋은 방법 제안"과 "현재 코드가 틀렸다" 혼동하지 않음