=== 컬럼명칭 통일 (c{prefix} → C-{prefix}11) ===
Python 분석스크립트: data pkl 경로 →
gen_temp_profiles: tempref 파일명 →
SteamAdvisorController: TagsFor() 숫자서픽스 → 풀컬럼키(C-6111), ToSuffix() 변환
steam.js: ST_TEMP_COLS ['61',...] → ['C-6111',...], selectbox defaultColumn
appsettings.json: Columns 키 c61/c62/... → C-6111/C-6211/..., DefaultColumn c6111→C-6111
run_column.py: 추출/분석시 col_key = f"C-{{prefix}}11"
C-{x}11_{model,tempref}.json: 신규 명칭 기준 기준프로파일/모델 7컬럼분
=== SteamAdvisor 수정 ===
SteamModel: [JsonPropertyName] 매핑(snake_case → PascalCase 역직렬화)
예외처리: LinearCoeffs.Count < 3 방어코드
steam.js: catch(_) {} → 에러메시지 표시, missing_tags 응답처리
=== Feedforward Controller 개선 ===
ff.js: 상승/하강 양방향 램프 confirm, 방향뱃지(↑↓), Normal 모드 표시
FeedforwardController: 업램프 단독제한 제거(양방향), tcReturnTcTarget/Band 노출
=== DB ===
Hc900DbContext: realtime_table_tagname_key 레거시 UNIQUE 제약/인덱스 DROP 로직
Hc900Controllers: ToDictionaryAsync → GroupBy 변환 (중복 tagname 대응)
=== SIGPIPE 대응 ===
gateway.cpp: signal(SIGPIPE, SIG_IGN) 메인스레드 설치
modbus_tcp.cpp: send() flags 0 → MSG_NOSIGNAL (EPIPE 복구)
sigpipe_ignore.c: LD_PRELOAD 우회 공유라이브러리
Hc900GatewayProcessService: LD_PRELOAD 환경변수 설정
9.9 KiB
진단 — Steam Advisory 라이브 차트 데이터 불로딩 (2026-06-06)
증상
Steam Advisory 탭 → "라이브" 패널에서 "조회" 버튼 클릭 후 차트와 입력값이 표시되지 않음.
진단 결과
🔴 HIGH — ToDictionaryAsync 중복 tagname ArgumentException
문제: SteamAdvisorController.Live와 TempProfile API에서 _ctx.RealtimePoints.Where(...).ToDictionaryAsync(r => r.TagName, ...) 사용. realtime_table의 UNIQUE 제약이 (controller_id, tagname)이므로 같은 tagname이 여러 controller_id로 존재할 수 있음. ToDictionaryAsync는 중복 키에서 ArgumentException을 던짐.
근거:
SteamAdvisorController.cs:133-135—ToDictionaryAsync(r => r.TagName, r => r.LiveValue)SteamAdvisorController.cs:194-196— 동일 패턴Hc900Controllers.cs:279-281— 동일 패턴Hc900DbContext.cs:488-498— UNIQUE 제약이(controller_id, tagname)
영향: API 호출 시 ArgumentException 발생 → 500 Internal Server Error → JS catch (_) {}로 삼켜짐 → 사용자에게 아무 표시도 없음.
수정: GroupBy(r => r.TagName).ToDictionaryAsync(g => g.Key, g => g.OrderByDescending(r => r.Timestamp).FirstOrDefault()?.LiveValue)로 변경. 최신 타임스탬프의 값을 사용.
🟠 MED — JS catch (_) {}로 예외 삼킴
문제: stLiveTick의 catch (_) {}가 API 에러를 완전히 무시. missing_tags 응답도 stUpdateLive에 전달되어 d.recOp가 undefined인 상태로 UI 갱신 시도.
근거: steam.js:163-169 — catch (_) {}
영향: API 에러가 발생해도 사용자에게 표시되지 않음. 디버깅 불가.
수정: catch (e)로 변경 후 st-live-msg에 에러 메시지 표시. missing_tags 응답은 별도 처리.
🟡 LOW — register-map에 없는 태그 존재
문제: appsettings.json의 SteamAdvisor 태그 중 9차, 9-2차, 10-1차, 10-2차 관련 태그가 register-map.json에 없음.
근거: appsettings.json:76-80 — 9차/10차 태그 정의. register-map.json에 해당 태그 없음.
영향: 해당 컬럼 선택 시 missing_tags 응답. 6차(C3)는 정상 동작.
수정: register-map에 태그 추가 또는 appsettings에서 제거.
교차 검증
| 질문 | 확인 방법 | 결과 |
|---|---|---|
| Q1. 이미 수정된 문제인가? | 파일 현재 상태 확인 | ❌ 수정되지 않음 |
| Q2. 다른 레이어에서 처리되고 있는가? | 호출 계층 확인 | ❌ JS catch (_) {}로 삼킴 |
| Q3. 의도적 설계인가? | 문서·주석 확인 | ❌ 의도적 아님 |
| Q4. 실제 장애 시나리오가 있는가? | 재현 경로 구체화 | ✅ 같은 tagname이 여러 controller_id로 존재하면 500 Error |
수정 내역
| 파일 | 변경 내용 |
|---|---|
SteamAdvisorController.cs:133-136 |
ToDictionaryAsync → GroupBy + FirstOrDefault |
SteamAdvisorController.cs:194-197 |
동일 패턴 수정 |
Hc900Controllers.cs:279-282 |
동일 패턴 수정 |
steam.js:163-176 |
catch (_) {} → 에러 표시 + missing_tags 처리 |
재평가 (2026-06-06, 코드·DB 데이터 검증 후)
진단을 데이터로 검증한 결과, #1의 "현재 장애 원인" 진술은 부정확하나, 위험의 본질은 설계상 유효함. 정정·심화:
#1 재평가 — "현재 ArgumentException 발생"은 거짓, 그러나 위험은 실재
- 현 데이터:
realtime_table에tagname단독 UNIQUE 인덱스(realtime_table_tagname_key)가 존재 → tagname 전역 유일 → 현재 중복 0행 →ToDictionaryAsync지금은 안 터짐. 즉 현재 불로딩의 원인이 아님. - 그러나(핵심): HC900은 컨트롤러 간 peer 통신으로 동일 태그를 미러링함. 설계상 같은 tagname이 여러
controller_id로 존재 가능하며, 올바른 제약은UNIQUE(controller_id, tagname)(메모리·idx_realtime_table_ctrl_tag_unique와 일치). - 진짜 버그: 현재 공존하는
tagname단독 UNIQUE 제약이 설계 위반. C4 online 시 peer 미러 태그의 두 번째 INSERT/upsert를 막아 적재 자체가 깨짐. - 결론:
ToDictionaryAsync → GroupBy수정은 단독 UNIQUE 제거를 전제로 방어적으로 정당. 단 "현재 500 에러 발생"은 아님(잠재 위험).
추가로 필요한 근본 수정 (진단보다 한 겹 깊음)
realtime_table_tagname_key(tagname 단독 UNIQUE) 제거 — 멀티컨트롤러 peer 적재 정합.(controller_id, tagname)만 유지.Live/TempProfile조회를controller_id로 한정 — 컬럼→컨트롤러 매핑(6차=C3 등)으로 필터. tagname만으로 조회하면 peer 미러된 동명 태그의 엉뚱한 컨트롤러 값이 섞일 수 있음(GroupBy로 예외는 막아도 어느 컨트롤러 값인지 모호).
실제 현재 불로딩 원인
- 6차(
C-6111) 필수 태그(FICQ-6101.PV·FICQ-6118.PV·TI-6111C)는 realtime에 모두 존재(C3) → 6차 선택 시 정상 동작해야 함. - 표면 트리거 = 기본 선택 컬럼이
configured알파벳순 첫(C-10111=10차) → 조회 시 C4 태그 부재 →missing_tags→catch(_){}(#2)로 삼켜져 무표시. - 해법:
DefaultColumn=C-6111로 변경 + UIstLoadColumns에서 기본 선택을C-6111으로 강제(작업플랜 4-3) +missing_tags사용자 표시(#2 수정으로 반영됨). #3(9·10차 태그 부재)은 사실.
종합
| 항목 | 진단 주장 | 재평가 |
|---|---|---|
| #1 ToDictionaryAsync | HIGH·현재 500 | 현재는 미발생(tagname 단독 UNIQUE)이나 peer 설계상 잠재 실재 → GroupBy 정당 + 단독 UNIQUE 제거·controller_id 한정 조회가 근본 |
| #2 catch 삼킴 | MED | 타당(표면 원인을 가림) |
| #3 9·10차 태그 부재 | LOW | 타당 + 기본 컬럼이 10차라 첫 화면 불로딩 트리거 |
추가 진단 — 컬럼명칭 혼재 문제 (2026-06-06)
🟠 MED — c6111/c61 중복 + 3가지 네이밍 체계 혼재
문제: appsettings.json에서 c6111과 c61이 같은 태그 매핑을 가리킴. ListModels API는 둘 다 반환 → UI에서 중복 선택 가능. 또한 컬럼키(c6111), 파일prefix(c6111/c61), TempProfile route param(61)이 각각 다른 규칙 사용.
근거: appsettings.json:73-74 — c6111과 c61 중복. SteamAdvisorController.cs:184 — c{col}_tempref.json (col = numeric suffix). steam.js:74 — ST_TEMP_COLS가 numeric suffix 사용.
영향: UI 컬럼 선택에서 중복, TempProfile API 호출 시 컬럼키 ↔ numeric suffix 변환 누락 가능성.
해결: 작업플랜-스팀컬럼명칭통일.md 참조. 컬럼키·파일prefix 모두 C-6111 형식으로 통일.
🟡 LOW — TagsFor numeric suffix 불일치
문제: TagsFor가 "61", "62" 등 2자리 numeric suffix를 기대하지만, 컬럼명칭 통일 후 "6111", "6211" 등 4자리로 변경됨. 템플릿 $"TICA-{p}11A.PV" → $"TICA-{p}A.PV"로 변경 필요.
근거: SteamAdvisorController.cs:249-268 — TagsFor 메서드.
영향: 컬럼명칭 통일 후 수정하지 않으면 태그명 생성 실패 → missing_tags 응답.
해결: 작업플랜-스팀컬럼명칭통일.md 작업 2-5 참조.
통일 작업플랜 보완 진단 (2026-06-06)
작업플랜-스팀컬럼명칭통일.md에 명칭 통일 방향은 타당하나, 원래 증상(라이브 불로딩) 해결과 Python 영향 범위가 과소평가됨.
🔴 누락 A — 통일해도 라이브 불로딩 재현 (UI 기본선택 강제 누락)
- 통일 후에도
OrderBy(x)알파벳순 첫은C-10111(1 < 6) →st-col첫 옵션 자동선택 = 데이터 없는 10차 →missing_tags→ 불로딩 그대로 재현. DefaultColumn=C-6111(작업1)은 Live API의col누락 시 fallback일 뿐, UIselect기본선택과 별개(steam.js stLoadColumns가 첫 옵션 선택).- 해결:
stLoadColumns에서 기본 선택을C-6111으로 강제 (작업플랜 4-3).
🟠 누락 B — Python c{prefix} 접두 패턴 (작업5 과소평가)
run_column.py:51—f"c{prefix}_data.pkl",gen_temp_profiles.py:38—f"c{prefix}_data.pkl",gen_temp_profiles.py:71—f"c{prefix}",gen_temp_profiles.py:75—f"c{prefix}_tempref.json".- prefix=
C-6111이면"cC-6111_data.pkl"로 깨짐. - 해결: 스크립트 내부
c{prefix}→{prefix}패턴 변경 +gen_temp_profiles.py:71의"column": f"c{prefix}"→"column": prefix.
추가 진단 — 컬럼명칭 혼재 문제 (2026-06-06)
🟠 MED — c6111/c61 중복 + 3가지 네이밍 체계 혼재
문제: appsettings.json에서 c6111과 c61이 같은 태그 매핑을 가리킴. ListModels API는 둘 다 반환 → UI에서 중복 선택 가능. 또한 컬럼키(c6111), 파일prefix(c6111/c61), TempProfile route param(61)이 각각 다른 규칙 사용.
근거: appsettings.json:73-74 — c6111과 c61 중복. SteamAdvisorController.cs:184 — c{col}_tempref.json (col = numeric suffix). steam.js:74 — ST_TEMP_COLS가 numeric suffix 사용.
영향: UI 컬럼 선택에서 중복, TempProfile API 호출 시 컬럼키 ↔ numeric suffix 변환 누락 가능성.
해결: 작업플랜-스팀컬럼명칭통일.md 참조. 컬럼키·파일prefix 모두 C-6111 형식으로 통일.
🟡 LOW — TagsFor numeric suffix 불일치
문제: TagsFor가 "61", "62" 등 2자리 numeric suffix를 기대하지만, 컬럼명칭 통일 후 "6111", "6211" 등 4자리로 변경됨. 템플릿 $"TICA-{p}11A.PV" → $"TICA-{p}A.PV"로 변경 필요.
근거: SteamAdvisorController.cs:249-268 — TagsFor 메서드.
영향: 컬럼명칭 통일 후 수정하지 않으면 태그명 생성 실패 → missing_tags 응답.
해결: 작업플랜-스팀컬럼명칭통일.md 작업 2-5 참조.