Files
MBN_STOCK_WEBVIEW/docs/LEGACY_PARITY_VALIDATION_20260715.md

16 KiB

LegacyParityApp 이관 검증 증적 — 2026-07-15

이 문서는 현재 MBN_STOCK_WEBVIEW.LegacyParityApp의 구현 증적과 지금 채택할 수 있는 검증 경계를 한곳에 모은다. 2026-07-15의 signed Release MSIX 설치·실행, 실제 마우스/CDP UI 동작과 제한된 Live 연결 실측은 아래 범위로 기록한다. 병렬 변경 전체의 최종 Debug/Release 및 Web 회귀 수는 확정했지만, scene PREPARE/TAKE IN/PGM 출력은 이 회차의 증적으로 확정하지 않는다. 원본 C:\Users\MD\source\repos\MBN_STOCK_N은 모든 조사와 테스트에서 읽기 전용으로 취급했다.

제품 형태와 권위 경계

항목 결과
제품 형태 .NET 8 / C# / WinUI 3 / Windows App SDK 1.8 / WebView2 / x64 / MSIX Windows 데스크톱 앱
웹사이트 여부 웹사이트가 아님. WinUI 3 프로세스가 패키지의 로컬 Web 자산을 WebView2로 표시
업무 권위 LegacyOperatorController의 C# 상태와 검증된 DTO가 권위
Web 경계 LegacyBridgeProtocol의 strict JSON intent allowlist; Web은 DB identity, scene alias, playlist 또는 송출 상태를 확정하지 않음
벤더 경계 COM/K3D/Tornado 구현은 IPlayoutEngine 뒤에 격리하고 STA 큐와 안전 게이트 유지
기본 송출 모드 DryRun; Live는 별도 개발 설정, 프로세스별 승인, allowlist와 명령 예산 필요
VS Development Live 정확한 --development-live + Debug + Git 제외 strict 로컬 승인 파일이 모두 맞을 때만 process-scope Live 설정; Release와 오류 경로에서는 이 bootstrap이 Live를 새로 설정하지 않음
불명확 결과 timeout/OutcomeUnknown에서 자동 재시도·반대 명령·추측 cleanup 금지

원본 UI와 클릭 이벤트

범위 현재 증적
Designer 전수 감사 원본 Designer 구독 186개, 화면별 고유 핸들러 171개를 IMPL/DEAD/VISUAL/DRAG/SAFETY로 전수 분류
업무 탭 원본 10개 탭, identity 기반 활성화와 순서 변경
종목 영역 모든 탭에서 유지되는 종목 검색, 결과, 31개 컷과 playlist 추가
고정/업종/비교 fixed 328개, 업종 44개, 비교 대상 24개와 action 9개를 폐쇄형 inventory로 고정
독립 클릭 UC4 테마, UC6 전문가, UC7 거래정지의 원본 단일 클릭과 UC4/UC6 행별 독립 처리
전용 입력 GraphE, FSell, VI, PList, AList, ThemeA, EList를 WebView 화면과 C# intent로 연결; ThemeA exact-title 중복확인 포함
해외 UC5 해외업종·해외종목·해외지수 조회와 playlist 생성
playlist F8 후보와 Ctrl/Shift 삭제 선택 분리, enabled, 위/아래, 선택/전체 삭제와 drag source 단일 행 이동; PREPARED/PROGRAM/pending/unknown 변경 차단
FarPoint 대체 Web table로 표현하되 원본 클릭·더블클릭·정렬·이동·저장, 탭 dragover 교환과 UC6/EList opaque 행 drag 의미 유지

상세 이벤트 대조는 OPERATOR_UI_PARITY.md를 따른다.

이벤트·drag·중복확인 구현 증적

줄 단위 원본 근거는 LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md에 있다. 186개 구독/171개 고유 핸들러 수에는 선언만 있고 구독되지 않은 메서드를 넣지 않았다.

  • playlist drag는 opaque source/target rowId와 before/after만 Web에서 보내며, C#이 실제 drag source 한 행만 이동한다. Ctrl/Shift 집합은 삭제 선택으로 유지하고 체크박스 dragstart는 거부한다.
  • 시장 탭은 dragover 대상 진입 시 source/target identity와 예상 인덱스를 보낸다. C# 현재 순서가 예상값과 일치할 때만 교환하므로 같은 전달의 재처리는 no-op이다.
  • UC6의 FpSpread2.AllowDragDrop은 ThemeA/EList 편집 행의 opaque rowId 재정렬로 이관했다. Web이 DB identity나 play index를 정하지 않는다.
  • ThemeA 중복확인은 이름 하나만 strict intent로 받고 C#이 현재 KRX/NXT provider에서 exact title parameterized read를 수행한다. 불명 결과는 Indeterminate이고 write나 fallback이 없다. edit 자기 행을 제외하지 않는 원본 규칙도 유지한다.

2026-07-15 실제 마우스/CDP UI 검증

설치한 현재 Release package의 실제 WebView 화면에서 다음 운영자 입력을 확인했다.

  • 삼성 검색 결과는 63개였고 삼성출판사를 선택했다. 컷 3개를 선택한 뒤 한 번의 drop으로 playlist에 정확히 3행을 추가했다.
  • 당시 package에서는 playlist 여러 행을 한 블록으로 재정렬했고, enabled 체크박스에서 시작한 drag는 행 이동을 만들지 않았다. 이후 원본 AllowRowMove 재감사에서 블록 이동은 근거 없는 확장으로 판정되어 현재 코드는 drag source 한 행만 이동하도록 교정됐다. 따라서 이 항목의 과거 block-drag 실측은 현재 단일 행 drag의 package 실측으로 재사용하지 않는다.
  • 시장 탭은 마우스 버튼을 놓기 전 dragover 대상 진입 시 순서가 바뀌었다.
  • EList 편집기에서 추천행 5개의 순서를 drag로 변경했다.
  • ThemeA 목록 500건을 불러온 상태에서 중복확인 exact-title read가 성공했다.

이 과정에서 playlist 행 drop이 조상 playlist-drop-zone으로 버블링해 아직 선택된 컷을 추가로 append하던 문제가 발견됐다. drop zone은 이제 exact legacy-selected-cuts text/plain token만 허용하고 playlist row custom MIME와 외부 text drop은 무시한다. 따라서 행 재정렬은 reorder-playlist-rows만 만들고 drop-selected-cuts를 만들지 않는다.

또한 Chromium은 체크박스를 눌러 시작한 경우에도 dragstart.target을 가장 가까운 draggable 조상 행으로 보고할 수 있어 단순 event.target.closest("input") 검사만으로는 부족했다. pointerdown 때 checkbox origin의 행 ID를 기억하고 이어지는 row dragstart를 거부하며, pointerup/pointercancel/dragend에서 상태를 지우도록 수정했다. thin-client 회귀 테스트는 이 Chromium target 형태, drag source 한 행만 전송, row drop의 ancestor 무시, 외부 text 거부와 exact selected-cut token의 단일 처리를 실제 DOM event 순서로 고정한다.

Development Live 시작 구성 증적

공유 .slnLaunch와 package launch profile은 LegacyParityApp을 시작 대상으로 고정한다. DEVELOPMENT_LIVE_VISUAL_STUDIO.md의 strict local authorization은 %LOCALAPPDATA% 아래 Git 제외 파일에 정확한 다섯 속성, 최대 4096바이트, canonical JSON, exact authorization 문자열과 독립 승인 native/Interop SHA-256을 요구한다. reparse, 알 수 없는/중복 속성, 파일 및 환경 설정 오류는 fail closed하며 authorization은 process scope에서 마지막에 설정된다. 이 부트스트랩은 기존 trusted Live 이중 게이트, scene allowlist, asset 검사와 timeout/OutcomeUnknown 정책을 대체하지 않는다.

실제 signed Release MSIX에 --development-live를 전달해도 compile-time Debug gate 때문에 승인 파일을 적용하지 않고 DryRun으로 실행되는 것을 확인했다. 이 Release DryRun 회차에는 Tornado TCP 연결이 없었고 Network Monitoring 내용도 변하지 않았다.

송출 흐름과 장면

항목 결과
원클릭 TAKE IN idle에서 보이는 TAKE IN/F8 한 번으로 PrepareAndTakeInAsync가 page load 1회, PREPARE 1회, TAKE IN 1회를 같은 게이트에서 수행
native PREPARE 엔지니어링 진단용 control/intent는 유지하되 운영자 UI에서는 hidden
실패 경계 PREPARE 후 TAKE IN 실패/unknown 시 prepared state 보존, 자동 재시도 없음
장면 기준선 원본 builder 35/35 inventory와 mutation/runtime 자동 기준선 통과
active alias 45개 alias의 대응 .t2s가 승인된 읽기 전용 Cuts에 존재
PageN 5·6·12개 단위, 최대 20페이지, 경계·마지막 부분 페이지·21페이지 거부 테스트
NEXT 같은 scene의 Page NEXT와 다음 enabled playlist 행 NEXT를 원본 조건으로 구분

실제 DB 검증

검증 결과
Oracle/MariaDB read-only PASS — 필수 scene selector 33/33, 전체 query 58건
GraphE write PASSINPUT_PIE, INPUT_GROW, INPUT_SELL, INPUT_PROFIT 각 create, fresh readback, delete, absence
PList/AList write PASS — named playlist 정의·항목 create/save, fresh readback, delete, absence
ThemeA KRX write PASS — create, preview/readback, delete, absence
ThemeA NXT write PASS — create, preview/readback, delete, absence
EList write PASS — expert create, preview/readback, delete, absence
ThemeA 중복확인 read PASS — 500건 목록 상태에서 현재 market의 exact title 조회; DB write 없음

개발 DB write는 총 9개 충돌 격리 시나리오다. production service/executor를 사용했으며 인증정보나 DB 원문을 출력하지 않았다. write 결과가 불명확한 경우에는 재시도와 cleanup을 하지 않는 구현·테스트 경계를 유지한다.

외부자산 판정

자산 상태 판정
45 active alias .t2s 존재 alias 준비 완료
s5006 Video\큐브배경.vrv 1개 없음 외부자산 미제공; 코드 실패 아님
s6001 국가별 영상 13개 없음 외부자산 미제공; 코드 실패 아님
sibling 배경\기본.vrv 없음 외부자산 미제공; F2/F3/default background는 fail closed

누락 자산은 Git 또는 MSIX에 임의로 넣지 않는다. 제공되면 같은 trusted-root, 0-byte, reparse, root-escape 검사를 통과한 뒤 해당 scene만 다시 검증한다.

2026-07-15 Tornado2 Live 연결 실측

아래 시각은 개발 장비 로컬 시간(KST)이다. strict local authorization을 통과한 제한된 Live 회차에서 14:28:28 HELLO request 1회와 success 1회, 14:43:10 BYE 1회를 Network Monitoring에서 확인했다. 이 회차의 scene 명령, PREPARE, TAKE 계열 명령과 DB write는 각각 0건이다.

종료 후 보관한 Network Monitoring 원문은 300,007자, SHA-256 45858322F60C135858002EB6243D0474F51F1965E23D2332D397C3A3B5DB8049다. 이 증적은 현재 코드의 Live CONNECT/handshake/DISCONNECT 경로만 확인한다. scene load/mutation, PREPARE, TAKE IN, NEXT/Page NEXT, TAKE OUT 또는 PGM 화면 출력을 검증했다는 뜻이 아니다.

별도의 Release DryRun 회차에서는 --development-live가 무시됐고 TCP 연결이 생성되지 않았으며 Network Monitoring 최종 내용도 변하지 않았다. 이는 Debug-only bootstrap 경계를 확인한 결과이지 Release Live 송출 결과가 아니다.

현재 package와 범위 회귀 기록

항목 2026-07-15 확인 결과
signed Release x64 MSIX 15,213,188 bytes, SHA-256 357E17426C45FF516592EE0177D0F95502A98AF084759348ABC191BA5ED21FD5
설치·실행 설치된 package-context 앱 실행 확인
Release --development-live Debug-only gate에 따라 무시되고 DryRun; TCP 연결과 Network Monitoring 변경 없음
실제 마우스/CDP UI 범위 삼성 63건 검색→삼성출판사→3컷 단일 drop, playlist multi-row reorder, checkbox drag 차단, tab dragover 교환, EList 5행 reorder, EList 수량 입력칸 origin drag 차단, ThemeA 500건과 중복확인 read 확인
제한된 Live Network 범위 HELLO request/success 각 1회와 BYE 1회; scene/PREPARE/TAKE/DB write 0
.NET Debug/Release x64 2,446/2,446, 실패·건너뜀 0, 경고·오류 0
Web Node 회귀 438/438, 실패·취소·건너뜀·TODO 0
Visual Studio 2026 build VS 18.7.3 / MSBuild 18.7.8, Debug·Release x64 모두 경고 0 / 오류 0

playlist drop MIME 경계, checkbox-origin drag와 EList input/button-origin drag 회귀는 thin-client DOM event 테스트로도 고정했다. 설치된 최종 Release package에서 실제 마우스로 EList 수량 입력칸에서 시작한 drag가 순서를 바꾸지 않고, 같은 행의 비입력 영역에서 시작한 drag만 5행 순서를 바꾸는 것도 확인했다. .NET Debug/Release 합계 4,892회와 Web 438회를 모두 통과했지만, scene PREPARE/TAKE/PGM을 실행하지 않은 이 Live 연결 회차를 전체 방송 송출 PASS로 확대하지 않는다.

코드 대조 Slice 1~10 합본 추가 검증

이후 원본 이벤트를 다시 코드 단위로 대조해 F8 후보·PROGRAM·DEL 다중선택·Shift anchor를 분리하고, 런타임 컷 50행, 종목/컷 키보드, UC1 tree, s8010 이동평균 재샘플링, K3D raw 인자와 OnCutOut/OnStopAll callback 게이트에 이어 child modal focus/Escape, PList 완료 순서와 Windows 컷 drag rectangle을 합쳤다. 이 합본의 검증 결과는 다음과 같다.

항목 추가 검증 결과
.NET Debug x64 2,611/2,611 통과, 실패·건너뜀 0
.NET Release x64 2,611/2,611 통과, 실패·건너뜀 0
Web Node 491/491 통과, 실패·취소·건너뜀·TODO 0
솔루션 Debug/Release x64 NuGet x64 복원 후 각각 경고 0 / 오류 0
Visual Studio 2026 MSBuild VS 18.7.8의 x64 MSBuild로 Debug/Release 솔루션 빌드 모두 성공
최신 unsigned Release MSIX 15,244,365 bytes, SHA-256 A2E9AA95B1F5E20C6E83A3B240A96F0E2792D3A1F809FEC60D829613BDF5CC8E
패키지 감사 78항목, Web 7개 source byte-for-byte 일치, .t2s·실설정·라이선스·인증서·K3D vendor 파일 0
package-context DryRun 최신 Release development registration에서 실행·응답, 인자 없음, DRY RUN UI, 앱 소유 TCP 0을 확인. 중립 종료창 프로그램을 종료하겠습니까?//아니요를 대조하고 를 1회 Invoke해 정상 종료

이 unsigned MSIX는 개발 package-context 실행 검증용이며 위 signed 배포 패키지를 대체하지 않는다. 이 추가 회차에서도 scene/PREPARE/TAKE/NEXT/DB write와 Tornado 연결은 실행하지 않았다. 새 컷 drag와 modal focus는 자동 계약까지 통과했으며 실제 package 마우스 drag 실측은 다음 대조 회차에 남아 있다.

컷 drag 임계값 후속 감사에서는 시작 시 한 번 읽던 GetSystemMetrics 캐시를 제거했다. 현재 구현은 GetSystemMetricsForDpi(SM_CXDRAG/SM_CYDRAG, 96) 결과를 host DIP 단위로 직렬화하고 XamlRoot.RasterizationScale/window.devicePixelRatio 비율로 pointer-event CSS pixel에 맞춘다. 따라서 100%·150% host DPI뿐 아니라 이전 profile에 남은 browser zoom도 보정하며 비정상 비율은 1로 닫힌다. WM_SETTINGCHANGE·WM_DISPLAYCHANGE·WM_DPICHANGED와 모든 state 게시 경계에서 값을 새로 읽고, cut-pointer-down 회신은 아직 시작되지 않은 gesture rectangle도 최신 값으로 다시 만든다. 이후 browser/pinch zoom 입력은 비활성화하며, native API를 사용할 수 없는 환경에서는 축별 4 DIP로 닫힌다.

PList 후속 대조에서는 WinForms DataSource 재지정의 첫 행 자동 선택을 복원하고, 행 선택에도 named-ui-* requestId와 exact command/target/sequence receipt를 적용했다. 따라서 2행 click 직후 확인·삭제가 과거 1행에 실행되지 않으며, double-click은 동일 ID의 선택 완료 뒤 한 번만 이어진다. known commit/read-back 실패는 warning을 유지한 성공으로, 현재 입력 검증 실패는 revision 미증가 실패로 구분하는 자동 회귀도 통과했다.

판정 경계

  • 35/35 자동 장면 동등성은 모든 장면의 실제 PGM 출력 완료를 뜻하지 않는다.
  • 33/33 DB selector 통과는 외부 영상/배경 자산 준비를 뜻하지 않는다.
  • 개발 DB 9개 write 시나리오 통과는 운영 DB에 쓰기를 허용하거나 수행했다는 뜻이 아니다.
  • 현재 signed Release MSIX의 설치·DryRun 실행, 실제 마우스/CDP UI, .NET Debug/Release 각 2,446개와 Web 438개 회귀를 확인했다.
  • Live 증적은 HELLO/BYE만 확인한 연결 회차다. scene/PREPARE/TAKE/DB write가 0이므로 PGM 송출 또는 원클릭 TAKE IN 전체 통합 성공으로 판정하지 않는다.
  • 원본 저장소, 실제 Cuts, 라이선스와 인증정보는 계속 읽기 전용 또는 Git 외부로 유지한다.