From 25fd969276b73a5b494e63e81bf161b1d6042e6d Mon Sep 17 00:00:00 2001 From: windpacer Date: Mon, 1 Jun 2026 17:16:41 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=ED=9B=84=EC=86=8D=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EC=A7=80=EC=8B=9C=EC=84=9C=20WP4-7=20(=EC=97=AD=EC=A0=84?= =?UTF-8?q?=E2=86=92recovery+=EC=BD=94=EB=9F=AC=EB=B3=B4,=20=EC=95=95?= =?UTF-8?q?=EB=A0=A5=EC=84=9C=EB=B8=8C=EC=8B=9C=EC=8A=A4=ED=85=9C,=20?= =?UTF-8?q?=ED=8E=B8=EC=B0=A8trim,=20=ED=94=84=EB=A1=A0=ED=8A=B8UI)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- .../안전피드램프-후속작업-작업지시서-WP4-7.md | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 plans/안전피드램프-후속작업-작업지시서-WP4-7.md diff --git a/plans/안전피드램프-후속작업-작업지시서-WP4-7.md b/plans/안전피드램프-후속작업-작업지시서-WP4-7.md new file mode 100644 index 0000000..1a68469 --- /dev/null +++ b/plans/안전피드램프-후속작업-작업지시서-WP4-7.md @@ -0,0 +1,147 @@ +# 작업지시서 — 안전 피드램프 Advisory 후속 (WP4~WP7) + +> 작성 2026-06-01. 다른 LLM/개발자 단독 실행용. 사전 맥락 없이 이 문서 + 참조로 수행. +> 컬럼 C-6111. **선행 통독 필수**: `docs/안전피드램프-한계치-브레인스토밍.md`(§0~§10), `plans/안전피드램프-advisory-작업지시서.md`(WP0~WP3), `docs/안전피드램프-검증시나리오매트릭스.md`. + +--- + +## 0. 현재 상태 (main, 커밋 ~4e1dfc1까지 완료) + +이미 구현·검증된 것: +- **버그픽스**: FeedforwardConfigStore ordinal off-by-one, FeedforwardEngine.ApplyFront front 부호(상단−하단). +- **WP0 Sim Override**: `SimOverrideStore`(ISimOverrideStore), `GET/POST/DELETE /api/ff/sim/override`, `appsettings Feedforward:SimOverrideEnabled=true`(DEMO 게이트). **엔진까지 통합**(`FeedforwardSupervisor.BuildSnapshotAsync` override 우선) + 안전가드(`_sim.Enabled` 시 auto-write 억제). +- **WP3 FeedRampAdvisor**: `FeedRampCalculator`(순수), `FeedRampAdvisorService`, `GET /api/ff/ramp-advisor`, DTO `FeedRampModels.cs`. +- **§10 역전판정**: `TempProfileJudge`(순수), 엔진 `JudgeTempProfile`(탑정 D 제외, spanRef 시드, 역전/붕괴 시 front trim HOLD), `AdvisoryResult.{TempProfileState,InversionPair,TempSpan,TempSpanRef}` + 컨트롤러 노출. +- 테스트 37/37, 라이브 S1~S5·S7·front·역전 검증 완료. + +## 0.1 공통 제약 (전 WP) +1. **쓰기 금지**(OPC/제어 SP)는 advisory 전부에 유지. WriteGuard·ARM 경유만 실쓰기(기존). 신규 advisory는 계산/표시만. +2. **DEMO**: 실시간 값 = SP + 일정변동 반복(합성). 물리 동특성 추정 금지. temps는 비물리(공간구배 미인코딩) → 물리 검증은 override로 단조/특정 프로파일 주입해야. +3. **Sim Override로 자율검증**: `POST /api/ff/sim/override {enabled,values:{"tag.pv":v}}` → 엔진/ramp-advisor 모두 반영(~2s tick). 단 stale(S6)은 불가(override=항상 fresh), transient(P4)는 `FeedMoveThresholdPerMin>0` 필요. +4. **JSON**: 신규 응답은 컨트롤러에서 **익명객체 camelCase 매핑**(기존 `MapColumn`/`MapRamp` 패턴). 비유한(NaN/Inf)은 null로. +5. **빌드/테스트**: `dotnet build src/Web/ExperionCrawler.csproj`(경고0/에러0), `dotnet test tests/ExperionCrawler.Tests/ExperionCrawler.Tests.csproj`. +6. **커밋**: 기본 브랜치(main)면 브랜치 먼저. WP별 분리 커밋 권장. + +## 0.2 C-6111 핵심 (변경 없음) +- 스트림: P(ficq-6118,Commanded,K0.95,θ60,τ900,sp_max2000,rate30), R(ficq-6113,Commanded,K0.8), D(ficq-6114,LevelDriven,K0.02,lica-6113), B(ficq-6116,LevelDriven,K0.03,li-6111). feed=ficq-6101. +- 컬럼: pressure=pica-6111, **dtdp=0(PCT off)**, delta_p_tag=null, sensitive_tray_tag=null, temp_tags=`tica-6111a,ti-6111b,ti-6111c,ti-6111d`. +- 추가 태그: `pi-6111b.pv`(≈리보일러 진공압), `ti-6103.pv`(프리히터 공급온도), `ficq-6115.pv`(스팀 flow 측정), `tica-6111a.op`(스팀밸브 OP 직결). +- 레이아웃(위→아래): pica-6111/REFLUX DIST(R)/TI-6111D/상부PACKING(정류,D)/제품추출 P(70~75%)/TI-6111C(제품 pivot)/긴중간PACKING(주분리,B)/TI-6111B/PREHEATER DIST(피드,TI-6103)/하부짧은PACKING(stripping)/TICA-6111A 리보일러(pi-6111b≈여기)→B. +- **정상 온도 A>B>C>D 단조감소**. TI-6111D는 환류 서브쿨 오염(조성 proxy 부적합). + +## 0.3 코드 색인 +| 역할 | 경로 | +|---|---| +| 엔진 | `src/Infrastructure/Control/FeedforwardEngine.cs` (Tick/ComputeStream/ApplyFront/ApplyRecovery/JudgeTempProfile) | +| supervisor | `src/Infrastructure/Control/FeedforwardSupervisor.cs` (BuildSnapshotAsync, AutoWriteAsync) | +| 계산기/판정 | `FeedRampCalculator.cs`, `TempProfileJudge.cs` | +| 모델 | `src/Core/Application/Feedforward/FeedforwardModels.cs`, `FeedRampModels.cs` | +| config store/DDL | `FeedforwardConfigStore.cs`, `src/Infrastructure/Database/ExperionDbContext.cs` | +| 컨트롤러 | `src/Web/Controllers/FeedforwardController.cs` (route api/ff) | +| 프론트 | `src/Web/wwwroot/js/ff.js`, `index.html`, `css` | +| 테스트 | `tests/ExperionCrawler.Tests/` | + +--- + +## WP4 — §10 역전을 ApplyRecovery에 연동 + 코러보레이션 (난이도 中) + +### 목적 +온도 역전/붕괴를 전환류 복귀 트리거 severity에 추가하되, **단발 센서이상이 곧장 recovery를 트리거하지 않도록 코러보레이션**(ΔP/vloss 동반 시에만 공정으로 인정). + +### 단계 +1. `FeedforwardEngine.ApplyRecovery` 시그니처에 `string? tempProfileState` 추가. `Tick`에서 `tp.State` 전달(JudgeTempProfile 결과; 이미 계산됨). +2. 신호 정의: + - `sigInv = tempProfileState=="온도역전"`, `sigCollapse=="프로파일붕괴"`. + - **코러보레이션**: `corroborated = sigVloss || sigDp`(기존 severity 신호). + - `tempSevere = (sigInv||sigCollapse) && corroborated` → `severe |= tempSevere`. + - **비코러보(온도만)**: `sigInv && !corroborated` → severe 아님. 대신 advisory 메시지 "온도역전(센서 점검 권고 — ΔP/물질수지 정상)" 노출(새 필드 또는 modeReason 보강). +3. `SeverityText()`에 `tempSevere`면 "온도역전/붕괴" 추가. +4. (주의) ΔP 코러보는 WP6(pi-6111b→ΔP) 이후에야 유효. 그 전엔 vloss 코러보만 동작 → 코드는 둘 다 지원하되 ΔP 없으면 vloss로. + +### 산출물/합격 +- 단위테스트(`FeedforwardRecoveryTests`에 추가): ① 역전+vloss불균형 → severe(전환류 진입 경로), ② 역전 단독 → severe 아님 + 센서점검 메시지. +- 라이브: override로 (a)역전+B과추출(vloss) → recovery 트리거(RecoveryEnabled 필요), (b)역전만 → 트리거 안 됨. +- 빌드0/테스트 통과. + +--- + +## WP6 — 압력 서브시스템 깨우기 (§9) (난이도 中, WP4·WP5 선행 권장) + +### 목적 +pi-6111b를 활용해 **전탑 ΔP**(flooding) + **압력 프로파일 기반 PCT**를 활성화. 현재 dtdp=0·delta_p_tag=null로 dormant. + +### 단계 +1. **ΔP 파생**: `pi-6111b.pv − pica-6111.pv` = 전탑 ΔP. + - 옵션A(권장): supervisor/엔진에서 계산해 `pv.DeltaP`에 주입(현재 `cfg.DeltaPTag`로 읽는 구조). `BuildSnapshotAsync`에서 DeltaPTag 없으면 `pi-6111b − pica-6111`로 합성. + - flooding ceiling(ramp-advisor)·ApplyRecovery sigDp가 이 ΔP 사용. `DeltaPFloodLimit`(config, 현재 MaxValue) 운전값으로 설정. +2. **압력 프로파일 PCT**: 현재 `BuildTemps`가 단일 압력(cfg.PressureTag)+dtdp. 확장: + - 각 temp에 **국소 압력** 부여 = 높이 보간(또는 패킹가중): ti-6111d≈pica, tica-6111a≈pi-6111b, ti-6111c/ti-6111b=보간. 보간 비율은 config 또는 const(예: 높이 0/0.33/0.66/1.0 → 실제 표고 미상이라 우선 균등). + - `TempCorrection.PressureCompensated(raw, p_local, pRef_local, dtdp)`. pRef도 프로파일(또는 단일 pRef + 동일 dtdp). + - `dtdp`를 config에서 실측 보정계수로(현재 0). **dtdp=0이면 PCT=raw(무변경)** 유지. +3. config: `delta_p_tag`·`dtdp`·`delta_p_flood_limit`는 기존 컬럼 존재 → 값만 세팅(운전원/UI). 프로파일 보간 비율은 신규 const/config. + +### 산출물/합격 +- 단위테스트: dtdp≠0 + 프로파일 압력 → 각 temp pct가 국소압 반영(상·하 다른 보정). ΔP 합성 동작. +- 라이브: override로 pica/pi-6111b·temps 주입 → `/api/ff/advisory` temps.pct ≠ raw, flooding ceiling이 합성 ΔP 사용. +- **주의**: PCT 활성화는 §10 역전판정·front 입력을 바꾸므로 WP4 이후 회귀 확인. + +--- + +## WP5 — 편차 trim + 2-point sensitive tray (§8·§8.8) (난이도 高, 설계결정 필요) + +### 목적 +LevelDriven 드로우 권장을 `K×feed`(무한상승)에서 **[조성목표(분율×feed)] + [bounded 편차 trim]** 구조로. 편차는 §8.4 2-타임스케일. + +### ⚠ 선행 결정 (사용자 확인 필요 — 구현 전 질의) +- **조성 분율 입력 경로**: 랩 수동입력 / 온라인 분석기 / KB? 갱신 주기? (base = 분율×feed) +- **D 환류 서브쿨 처리**(§10.2-B): 상부 front에 TI-6111D 직접 사용 불가 → (b1)서브쿨 보정 (b2)C 단독 PCT (b3)D 재지정 중 택1. +- **편차 clamp/rate 한계**: 제거목표의 ±몇 %? rate ≤ 듀티 대역폭(상호작용 방지). +- **config 모델**: B/D를 LevelDriven→Commanded(조성구동) 재분류? li-6111 level_tag 강등? + +### 단계 (결정 후) +1. config 확장: `UpperSensitiveTrayTag`+`LowerSensitiveTrayTag`(ff_column_config 신규 컬럼 + ExperionDbContext boot DDL + FeedforwardConfigStore SELECT/INSERT/UPDATE + MapConfig). 또는 섹션별 차온쌍. +2. 2-point front: `FrontPositionIndicator` 2개 인스턴스(ColumnState). 상부=ΔT(TI-6111C−TI-6111D보정), 하부=ΔT(TI-6111C−TI-6111B). ApplyFront 섹션별 반환. +3. fast trim(초~분): 섹션 front 편차 → bounded trim(clamp+rate). B=하부, D=상부. +4. 귀속: vloss를 "프론트 드리프트하는 스트림"에 배분(상부 고정·하부 이동=B). +5. slow re-baseline(시간): vLossMa+랩분석 → base 분율 재보정(운전원 리뷰, 자동 아님). +6. SP 산출: `B_SP = 분율×feed + trim`(advisory; 쓰기는 기존 정책). + +### 산출물/합격 +- 단위테스트: 상/하 front 분리, trim 부호·clamp, 귀속. +- 라이브: override로 하부 front 드리프트 → B trim만, 상부 → D trim만. +- **범위 주의**: 가장 크고 설계 미확정. 1단계(2-point front + 표시) → 2단계(trim) → 3단계(조성base SP)로 **분할 권장**. + +--- + +## WP7 — 프론트 UI (ff.js) (난이도 中, 독립 진행 가능) + +### 목적 +운전원 화면에 ① 피드 램프 계산기 ② 온도 프로파일 상태(역전) 표시 ③ (개발용) sim override 패널. + +### 단계 +1. **램프 계산기 패널**(`#pane-ff` 또는 카드 상단): 입력 targetFeed/deltaIAllow/sensibleGain/feedTempRef/floodLimit → `GET /api/ff/ramp-advisor?columnId=&...` → 결과표(clampedTarget, ceiling{value,binding}, rampRate{value,binding}, rampTimeMin, steam{from,to}, warnings). camelCase 응답 그대로. +2. **tempProfileState 뱃지**: 카드에 `tempProfileState`(정상/약화/붕괴/온도역전) 색상 뱃지 + `inversionPair`·`tempSpan`. 역전 시 경고색 + frontTrim "HOLD" 표기. +3. **sim override 패널**(개발/데모 전용, `SimOverrideEnabled` 시만 노출): 태그-값 입력 → `POST /api/ff/sim/override`, `DELETE`로 해제. `simOverrideActive` 표시. +4. 기존 ff.js 패턴(`ffCard`, fetch, esc) 재사용. `node -c ff.js` 문법 확인. + +### 산출물/합격 +- 브라우저에서 램프 계산기 동작(입력→결과), 역전 뱃지 표시, sim 패널로 주입/해제. +- `dotnet build` 영향 없음(정적자산). Ctrl+F5 후 확인. + +--- + +## 권장 순서 +1. **WP4**(역전→recovery, 작음) → 2. **WP6**(압력/ΔP/PCT — WP4 코러보 ΔP 공급) → 3. **WP7**(UI, 독립) → 4. **WP5**(편차 trim, 설계결정 후 분할). + +## 검증 공통 (sim override 자율 루프) +``` +curl -s -XPOST localhost:5000/api/ff/sim/override -H 'Content-Type: application/json' -d '{"enabled":true,"values":{...}}' +sleep 3; curl -s localhost:5000/api/ff/advisory # 엔진 반영 +curl -s 'localhost:5000/api/ff/ramp-advisor?columnId=1&targetFeed=1100&...' +curl -s -XDELETE localhost:5000/api/ff/sim/override +``` +**앱 재기동** 필요(코드 변경 반영): 운전원이 `dotnet run` 재시작. + +## 참조 / 메모리 +- 메모리: `project_safe_feed_ramp_brainstorm`, `project_demo_system_synthetic_data`, `reference_json_serializer_pascalcase`, `project_sidedraw_ff_advisory`, `project_realtime_collector_stall`. +- `docs/안전피드램프-한계치-브레인스토밍.md` §7(편차/스팀)·§8(편차소스)·§9(압력)·§10(역전).