Files
HC900-Crawler/docs/작업플랜-FF온도계위젯-C민감단-sweetspot.md
windpacer 1f989bd861 feat: FF 온도계 위젯 + 민감단 모듈1 T_C 유지 SP 제안
위젯: AdvisoryResult에 config 시각화 필드 추가, ffThermometer() 세로 온도계 위젯 구현 (4단 마커+sweet spot 밴드+하한선+C편차 화살표+옵션 푸터)

모듈1: FeedforwardEngine SteamAdvisor DI + ResolveTcTemp, Normal 모드에서 T_C 유지 Steam OP 제안 (SteamAdvisor Predict + FB trim gain-0.6/dwell20분)
2026-06-07 08:22:43 +09:00

14 KiB

작업플랜 — FF 카드 세로 온도계 위젯 (T_C sweet spot) (2026-06-07)

상위: docs/작업지시서-STEAM-SP-FF통합.md ③단계(UI 행)의 시각화 컴포넌트. 설계 맥락: SteamAdvisor(steam=f(feed,product,T_C)→OP)를 FF 추종 프레임에 통합 중.

진단 (2026-06-07, diagnosis-checklist.md 적용)

# 심각도 항목 근거 파일·라인
1 🟠 MED 위젯이 Config 데이터에 접근할 방법 미정의 계획은 tcReturnTcTarget/tcReturnTcBand(밴드)와 sensitiveTrayTag(C 마커 식별)를 config 응답에서 가져온다고 하나, ffCard(c)는 오직 /api/ff/advisoryMapColumn만 인자로 받음. Config는 별도 /api/ff/config로 로드되어 ff-cfg-list에만 렌더 — ffCard 스코프에 config 데이터가 없다. 밴드 생략(마커만)으로 우회는 가능하지만, C 마커를 tag name 매칭 없이 index 추정(70%)에만 의존하면 컬럼별 TempTags 개수·순서 차이 시 오표시. wwwroot/js/ff.js:190 (ffCard(c) 호출, c는 advisory 전용), 대비 FeedforwardController.cs:381-459 (MapColumn에 config 필드 없음), 계획 §단계-1
2 🟡 LOW temps 순서 가정이 TempTags 설정 순서에 의존 계획(line 36)은 reb-A=temps[0], D=temps[n-1]를 가정하나, 이 순서는 DB TempTags 배열 순서에 전적으로 의존. BuildTemps(FeedforwardEngine.cs:177)는 주석으로 "하단→상단 순서"를 전제하지만 강제하지 않음. 운전자/엔지니어가 설정 화면에서 태그 순서를 잘못 입력하면 마커 라벨이 온도와 불일치. 계획(line 72-73)이 "향후 config화"로 명시하나 first-cut에서도 조치 필요. FeedforwardEngine.cs:177-205 (BuildTemps, 순서 검증 없음), 계획 §현자산 line 36, §주의 line 72-73
3 🟡 LOW 폴링 주기 불일치 (5s vs 3s) 검증기준(line 64)은 "5초 폴링마다"라고 명시했으나 ffInit(ff.js:25)는 setInterval(ffLoadDash, 3000)으로 3초. 온도계 갱신 주기도 동일 타이머를 공유하므로 문서와 실제 동작 간 차이 발생. 기능상 문제는 없으나 혼선 가능. 계획 §검증기준 line 64, 대비 ff.js:25
4 🟡 LOW C-index 70% fallback이 4-Temp 가정에 묶임 계획(line 51)은 sensitiveTrayTag 매칭 실패 시 "인덱스 추정(70%)"으로 C를 식별. C-6111은 4개 temps(index=2로 정확)이나, 3개 temps면 index=2(마지막), 5개면 index=3(80% 위치)으로 의도한 민감단과 다를 수 있음. sensitiveTrayTag가 config에 있고 advisory에 없으므로 사실상 항상 fallback에 의존할 가능성. 계획 §단계-1 line 51, FeedforwardController.cs:450-456 (MapColumn temps에 tag name 포함 — 매칭 가능은 하나 config 필드 없음)

교차검증 종합

  • Q1 (이미 수정됨?) — 해당 없음 (plan 문서, 아직 구현 전)
  • Q2 (다른 레이어 처리?) — #1: advisory 응답에 sensitiveTrayTag를 추가하거나, ffLoadDash가 config를 병렬 로드해 ffCard에 넘겨야 함. 현재 어느 쪽도 아님.
  • Q3 (의도적 설계?) — #1은 설계 누락(구현 시 발견될 문제). #2·#4는 계획이 인지한 범위 내 한계. #3은 단순 오기.
  • Q4 (재현 시나리오?) — #1: ffThermometer 구현 시 sweet spot 밴드 미표시 또는 C 마커 오식별. #2: TempTags 순서 실수 시 마커 라벨 혼동.

연계 진단 — 작업플랜-민감단온도-전환복귀제어.md와의 통합

# 심각도 항목 근거 관련 Plan
5 🟠 MED tcReturnTcTarget/Band가 시각화와 제어게이트를 겸함 — 안전 문제 위젯은 tcReturnTcTarget ± tcReturnTcBand를 sweet spot 시각화 밴드로 사용(계획 line 37-38). 동시에 엔진 ApplyRecovery()(FeedforwardEngine.cs:497-498)는 같은 필드를 복귀(Returning) 게이트 조건으로 평가함. 운전자가 시각화 편의를 위해 밴드를 넓히면 복귀 게이트가 느슨해져 T_C가 완전히 안정되지 않았는데 Normal 복귀 허용 위험. 두 용도가 동일 config 필드를 공유하는 것은 설계상 충돌. 민감단 §모듈3 line 57, FF위젯 §현자산 line 37-38, FeedforwardEngine.cs:497-498
6 🟠 MED 위젯에 TempLowLimit 미반영 — T_C 하한 경고 누락 엔진은 TempLowLimit(기본 -1e9=비활성)으로 T_C 하한 이탈을 감시(sigTLow, FeedforwardEngine.cs:444), 전환류 진입 트리거로 사용. 위젯은 sweet spot 밴드만 표시하고 TempLowLimit 경계를 표시하지 않음. TempLowLimittcReturnTcTarget - tcReturnTcBand보다 높게 설정된 경우(예: 목표±1℃ 대신 하한 -3℃), C가 sweet spot 밴드 안에 있어 초록이지만 실제로는 하한 임박 — 운전자 오인 유발. 위젯 온도계에 하한 임계선(적색 점선)을 추가하거나, 최소한 위험 상태 배지 연동 필요. 민감단 §모듈2 line 51, FF위젯 §단계-2 line 55-56, FeedforwardEngine.cs:444
7 🟡 LOW EnteredByTcLow가 advisory에 미노출 — 전환류 원인 표시 불가 엔진은 st.EnteredByTcLow(FeedforwardEngine.cs:46)로 전환류 진입이 T_C 하한 때문인지 기록하고, 복귀 게이트 분기(같은 파일 line 502)에 사용. 이 정보가 AdvisoryResultMapColumn에 없어 위젯이 "T_C 하한 진입" vs "물질수지/ΔP 진입"을 구분해 표시할 수 없음. 민감단 §큰그림, FeedforwardEngine.cs:46/469/502, FeedforwardController.cs:421-459 (MapColumn)
8 🟡 LOW TempLowLimit도 advisory에 미노출 — 위젯이 하한 임계선 표시 불가 MapColumn(FeedforwardController.cs:421-459)에 tempLowLimit 누락. 위젯이 하한 임계선을 그리려면 이 값이 필요. tempLowLimit은 엔진에서 읽지만 advisory 응답에 포함되지 않음. #6 해결의 선행조건. FeedforwardController.cs:421-459 (MapColumn), ColumnConfig.TempLowLimit
9 🟡 LOW 온도계 초록(정상)과 모드배지 간 시차 혼동 가능 위젯은 T_C가 밴드 안이면 즉시 초록(◉) 표시. 엔진은 Returning 게이트 조건(T_C in-band + reb-A in-band + ΔT(A-D) 안정)이 RecoverySettleSec(기본 1800s=30분) 지속되어야 Normal로 전이(FeedforwardEngine.cs:504). 따라서 운전자는 온도계는 초록인데 모드배지는 "전환류 평형대기 1200/1800s"인 상황을 30분간 보게 됨. 정상 동작이나 사전 안내 없으면 혼란. 민감단 §모듈3 line 57-58, ff.js:320-325 (모드배지), FeedforwardEngine.cs:497-504
10 🟡 LOW 온도계 마커가 Recovering 중에도 살아있어야 하나 미명시 전환류(Recovering) 중에도 T_C 온도는 유효하며, 운전자는 T_C가 회복되는 과정을 실시간으로 봐야 복귀 게이트 진행을 납득 가능. 위젯 계획(line 76)은 "표시 전용"이라 명시했으나 Recovering 중에도 위젯이 활성 상태를 유지하는지 미기재. c.temps가 Recovering 중에도 정상 제공되므로 별도 처리 불필요하나, 명시적 언급이 없으면 구현 시 실수로 숨길 가능성. FF위젯 §주의 line 76, §단계-1 line 51 (c.temps 조건부 표시)
11 🟡 LOW 하강 램프 시각화 미지원 민감단 계획(§4-A)은 FeedRampAdvisor 하강 램프 추가를 명시하나, FeedRampCalculator.Compute()(FeedRampCalculator.cs:87-88)는 아직 하강 미구현. 위젯은 이와 무관하지만, 램프 진행 중 온도계가 어떻게 변화하는지(특히 하강 램프가 T_C에 미치는 영향)를 보여주지 않으면 운전자 피드백 루프 불완전. 단, FF위젯 계획이 "표시 전용"이므로 직접 구현 범위 밖 — 인지하고 넘어갈 것. 민감단 §4-A line 62, FeedRampCalculator.cs:87-88

연계 교차검증

  • Q1 (이미 수정됨?) — #11의 하강 램프는 FeedRampCalculator에 여전히 미구현 상태 (Q1 통과)
  • Q2 (다른 레이어 처리?) — #5: 두 plan 모두 동일 config 필드를 각자 용도로 참조하므로, 다른 레이어에서 해소되지 않음. #7·#8: advisory DTO가 누락 — MapColumn에 필드 추가 필요.
  • Q3 (의도적 설계?) — #5: 의도적이 아니라 간과된 설계 충돌. #9: 정상 동작이나 UX 관점에서 명시 필요. #10: 위젯 계획에 명시적 언급 없음.
  • Q4 (재현 시나리오?) — #5: 운전자가 설정 화면에서 밴드를 1.0→2.0으로 늘리면, 복귀 게이트가 T_C 편차 ±1℃→±2℃로 완화되어 T_C 미회복 상태에서 Normal 조기 복귀 가능. #6: TempLowLimit=207℃, sweet spot=209±1℃일 때 T_C=207.5℃는 밴드 밖이지만 위젯이 하한 임계를 표시하지 않아 "노랑(▲)"만 보고 운전자 대응 늦어짐. #9: 초록 온도계 + "전환류 중" 배지를 30분간 보며 혼란.

목적

유량권장(FF) C-6111 카드 옆에 세로 온도계(thermometer) 위젯을 붙여, 민감단 온도 T_C가 제품별 목표(설정값) ± 허용대역(sweet spot) 대비 처지는지(▼) / 올라가는지(▲)를 운전자가 한눈에 보게 한다. reb-A·B·C·D 4단을 같은 온도축에 함께 표시해 컬럼 단면 프로파일까지 한 그림에 담는다.

선택된 형태 (결정됨)

세로 온도계 스냅샷 (트렌드 막대/스크롤 아님 — steam 패널 uPlot 트렌드와 중복 회피).

  • 세로축 = 온도(℃). "처짐/상승" = 마커의 아래/위 이동으로 직결.
  • sweet spot = 반투명 두꺼운 밴드(목표 ± 허용). 밴드 안에 C가 있으면 정상.
  • reb-A(0%·bottom)·B(50%)·C(70%·민감단)·D(90%·top) 4개 마커. 각 단 라벨에 % 표기.
  • C가 밴드 하한 아래로 처지면 ▼ 적색, 상한 위면 ▲ 주황, 안이면 초록.
  • (옵션 푸터) 신뢰도 + 권장 TICA SP — 백엔드 공백 해소 후.
  T_C 온도계 (℃)
 222 ┤◀ reb-A  0%(bottom)
 213 ┤◀ B      50%
 ░░░░░ 211  sweet 상한
 ░░◉░░ 209 ◀ C 70% ★목표
 ░░░░░ 207  sweet 하한
 201 ┤◀ D      90%(top)
 ─────────────────
 conf HIGH · TICA SP→209      ← (옵션, 백엔드 공백)

현 자산 (재활용, 중복금지)

프론트(/api/ff/advisory + /api/ff/config)에 이미 도달하는 데이터:

  • 현재 단별 온도c.temps[] = {tag, raw, pct, good}, 하단→상단 순서 (FeedforwardEngine.BuildTemps 주석: tica-6111a(0%), ti-6111b, ti-6111c(민감단), ti-6111d(top)). → reb-A=temps[0], C=민감단=sensitiveTrayTag 매칭(또는 70% 위치), D=temps[n-1].
  • sweet spot 밴드/api/ff/configtcReturnTcTarget(목표℃) ± tcReturnTcBand(반폭, 기본 1.0) (FeedforwardController.cs:222-223에서 이미 직렬화). 운전자 입력 설정값 = 이 값.
  • 상태색 보조c.tempProfileState, c.tempSpan.
  • 카드 렌더 진입점: wwwroot/js/ff.js ffCard(c) (257행~). CSS: 동일 ff 스타일시트.

백엔드 공백 (옵션 푸터에만 필요) ⚠

스팀 제안(SteamAdvisor.PredictRecOp/RecSteam/Confidence/Ood)이 FF advisory DTO(MapColumn)에 아직 미노출 (Feedforward 폴더 grep 0건).

  • 온도계 본체(밴드+4마커+처짐/상승색)는 공백과 무관하게 1차 구현 가능.
  • 푸터의 "conf · TICA SP→" 표시는 작업지시서-STEAM-SP-FF통합 ①단계 (AdvisoryResult에 Steam 필드 추가 → MapColumn에 노출)가 선행돼야 함.

단계

  1. 데이터 셀렉터 (ff.js)c 한 개에서 온도계 입력 추출:
    • temps = c.temps(없으면 위젯 미표시), C = sensitiveTrayTag로 매칭하되 실패 시 인덱스 추정(70%).
    • 밴드 = config의 tcReturnTcTarget/tcReturnTcBand(없으면 밴드 생략, 마커만).
    • 스케일 = [min(저온, 밴드하한), max(고온, 밴드상한)] + 여유 5% 패딩.
  2. 렌더 (ff.js)ffThermometer(c) 함수 신설. SVG 또는 div+CSS 세로 막대.
    • 밴드 사각형(반투명), 4단 마커(틱+라벨+값), C 강조(◉).
    • C 위치 판정 → 클래스 ff-tc-low/ok/high로 색/화살표.
  3. 카드 결합 (ff.js)ffCard 반환 마크업에 ffThermometer(c)를 카드 우측 컬럼으로 삽입 (기존 카드를 flex 2열: 좌=표/배지, 우=온도계).
  4. CSS.ff-thermo(세로 트랙), .ff-thermo-band, .ff-thermo-mark, .ff-tc-low/ok/high. live 갱신 시 top 트랜지션으로 마커가 부드럽게 이동(0.3s).
  5. (옵션) 푸터 — ①단계 백엔드 노출 후 conf + recSteam/recOp 한 줄. 없으면 숨김.

검증기준

  • C-6111 카드 옆에 온도계 표시, 5초 폴링마다 4단 마커가 live 이동.
  • T_C가 밴드 안 → 초록·◉ 밴드 중앙 근처. 밴드 아래로 내리면 ▼ 적색, 위면 ▲ 주황.
  • tcReturnTcTarget 미설정 컬럼 → 밴드 없이 마커만(에러 없음).
  • c.temps 없음/stale → 위젯 graceful 미표시 또는 회색.
  • (옵션) ①단계 적용 시 푸터에 conf+SP 표시, 미적용 시 푸터 숨김.

주의

  • range는 realtime/config live값 사용 — xlsx·하드코딩 금지(메모리·작업지시서 일관).
  • 단 라벨 %(0/50/70/90)는 C-6111 레이아웃 기준 표시값. 컬럼별 상이 시 향후 config화 (현재 BuildTemps 주석도 C-6111 고정 — 일반화는 별도 작업).
  • reb-A가 온도축 최상단(최고온)에 오는 건 정상(물리 높이가 아닌 온도축이므로). 라벨로 명시.
  • 6차만 C3 online → first-cut은 C-6111. 9·10차(C4 미연결)는 데이터 도달 시 자동 적용.
  • closed-loop 강제·자동쓰기와 무관한 표시 전용 위젯(메모리: 조건 실변동중 — 시각화만).

권장순서

①셀렉터+렌더(공백 무관) → ②CSS → ③카드결합 → ④(백엔드 ①단계 후)푸터. ①~③은 STEAM-SP-FF통합 백엔드와 독립 병행 가능.