feat: restore legacy drag events and Tornado launch integration
This commit is contained in:
130
docs/DEVELOPMENT_LIVE_VISUAL_STUDIO.md
Normal file
130
docs/DEVELOPMENT_LIVE_VISUAL_STUDIO.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Visual Studio 2026 개발 Tornado Live 실행
|
||||
|
||||
## 목적과 안전 기본
|
||||
|
||||
이 문서는 개발 PC의 Visual Studio 2026에서 `MBN_STOCK_WEBVIEW.LegacyParityApp`을
|
||||
명확한 시작 대상으로 실행하고, 개발 Tornado2에 연결하는 방법을 설명한다.
|
||||
|
||||
저장소의 송출 기본값과 Release 동작은 계속 `DryRun`이다. 개발 Live는 다음 세 조건이
|
||||
동시에 맞는 **Debug 프로세스 한 회차**에서만 기존 Live 게이트를 설정한다.
|
||||
|
||||
1. 시작 인자가 정확히 `--development-live` 하나이다.
|
||||
2. 컴파일된 앱이 Debug 빌드이다.
|
||||
3. 아래 Git 제외 로컬 승인 파일이 존재하며 엄격한 스키마 검사를 통과한다.
|
||||
|
||||
조건이 하나라도 다르면 환경 변수를 설정하지 않는다. 로컬 파일이 없거나 읽기 권한이
|
||||
없고, JSON 또는 해시 형식이 잘못된 경우에도 시작은 fail-closed로 진행되어 기존
|
||||
`playout.local.json`의 안전 기본인 `DryRun`을 사용한다.
|
||||
|
||||
## Visual Studio 시작 대상과 프로필
|
||||
|
||||
공유 솔루션 실행 프로필은 저장소 루트의
|
||||
`MBN_STOCK_WEBVIEW.slnLaunch`에 있으며 다음 프로젝트만 시작한다.
|
||||
|
||||
```text
|
||||
src\MBN_STOCK_WEBVIEW.LegacyParityApp\MBN_STOCK_WEBVIEW.LegacyParityApp.csproj
|
||||
```
|
||||
|
||||
`Debug|x64`와 `Release|x64`의 MSIX Deploy 대상도 루트 프로토타입이 아니라 이 프로젝트이다. Visual
|
||||
Studio의 시작 드롭다운에는 다음 두 프로필이 표시된다.
|
||||
|
||||
| 순서 | 프로필 | 동작 |
|
||||
|---:|---|---|
|
||||
| 1 | `MBN_STOCK_WEBVIEW.LegacyParityApp - Development Live (Package)` | `--development-live`를 전달한다. 유효한 로컬 승인 파일이 있을 때만 Live를 구성한다. |
|
||||
| 2 | `MBN_STOCK_WEBVIEW.LegacyParityApp - Explicit DryRun (Package)` | 개발 Live 인자를 전달하지 않는다. |
|
||||
|
||||
개발 PC에서 Live를 사용할 때는 공유 실행 프로필 `Legacy Parity App (VS F5)`, 구성
|
||||
`Debug`, 플랫폼 `x64`, 첫 번째 Development Live 패키지 프로필을 선택하고 F5를 누른다.
|
||||
DryRun 확인은 두 번째 프로필을 선택한다. 앱은 단일 인스턴스이므로 프로필을 바꿀 때
|
||||
기존 인스턴스를 정상 종료한 뒤 다시 실행해야 한다.
|
||||
|
||||
패키지된 WinUI 3 full-trust 실행에서는 Visual Studio가 프로세스 명령줄에 인자를 전달해도
|
||||
`LaunchActivatedEventArgs.Arguments`가 빈 문자열일 수 있다. 부트스트랩은 activation 인자가
|
||||
비어 있을 때에만 `Environment.GetCommandLineArgs()`가 정확히 `exe + 인자 1개`인 경우 그
|
||||
하나를 사용한다. 인자가 없거나 둘 이상이면 합치거나 일부를 무시하지 않고 Live 요청을
|
||||
거부한다. Release 빌드는 이 fallback으로 정확한 인자를 얻더라도 Debug-only gate에서
|
||||
승인 파일을 읽지 않고 기존 `DryRun` 설정을 유지한다.
|
||||
|
||||
## 로컬 승인 파일
|
||||
|
||||
실제 파일 경로는 다음과 같다.
|
||||
|
||||
```text
|
||||
%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\playout.development-live.local.json
|
||||
```
|
||||
|
||||
실제 파일명은 `.gitignore`에 포함되어 있다. 저장소의
|
||||
`Config\playout.development-live.example.json`을 구조 참고용으로 사용하되, 예제의
|
||||
해시 placeholder는 실행 가능한 값이 아니다. 실제 승인 파일은 정확히 다음 다섯 속성만
|
||||
가진다.
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"mode": "Live",
|
||||
"authorization": "I_AUTHORIZE_LIVE_PROGRAM_OUTPUT_FOR_THIS_LAUNCH",
|
||||
"nativeSha256": "<독립적으로 승인한 x64 K3D native DLL의 64자리 SHA-256>",
|
||||
"interopSha256": "<독립적으로 승인한 x64 K3D Interop DLL의 64자리 SHA-256>"
|
||||
}
|
||||
```
|
||||
|
||||
검사 규칙은 다음과 같다.
|
||||
|
||||
- 파일 크기는 1~4096바이트이다.
|
||||
- 파일과 `%LOCALAPPDATA%` 아래의 중간 디렉터리는 reparse point가 아니다.
|
||||
- JSON 주석, trailing comma, 중복 속성, 알 수 없는 속성, 대소문자가 다른 속성을
|
||||
허용하지 않는다.
|
||||
- `schemaVersion`은 숫자 `1`, `mode`는 정확히 `Live`, `authorization`은 위 문자열과
|
||||
정확히 일치해야 한다.
|
||||
- 두 해시는 공백 없는 64자리 16진수여야 한다. 경로나 DLL은 Git에 기록하지 않는다.
|
||||
- 파일 없음, 잘못된 경로, 공유 위반, I/O 또는 읽기 권한 오류는 모두 같은 제한된
|
||||
`authorization-unavailable` 결과로 처리하며 경로와 값은 로그에 표시하지 않는다.
|
||||
|
||||
현재 설치 파일의 해시를 그 자리에서 계산했다는 이유만으로 승인 값으로 사용해서는 안
|
||||
된다. 벤더 배포본 또는 기존에 독립 검수된 증적과 대조한 값을 사용한다. 파일 ACL은 현재
|
||||
개발 사용자와 관리자만 수정할 수 있도록 유지한다.
|
||||
|
||||
## 기존 playout.local.json
|
||||
|
||||
기존 설정 파일 경로는 그대로이다.
|
||||
|
||||
```text
|
||||
%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\playout.local.json
|
||||
```
|
||||
|
||||
이 파일의 `mode`는 `DryRun`으로 유지한다. Development Live 부트스트랩이 성공한 해당
|
||||
Debug 프로세스에서만 `MBN_STOCK_PLAYOUT_MODE=Live`를 process scope로 덮어쓴다.
|
||||
기존 이중 게이트를 유지하기 위해 로컬 설정에는 `trustedLiveOutputEnabled: true`가
|
||||
명시되어야 한다.
|
||||
|
||||
실제 cue의 `PlayoutCue.SceneName`은 builder의 대표 SceneCode가 아니라 활성 cut alias다.
|
||||
전체 이관 UI를 개발 PGM에서 검증할 때 `testSceneAllowlist`에는
|
||||
`LegacySceneRuntimeCoverage.ExpectedCutCodes`와 동일한 다음 45개 alias를 사용한다.
|
||||
|
||||
```text
|
||||
5001, 5006, 5011, 5016, 50160, 5023, 5024, 5025, 5026, 5029,
|
||||
5032, 5037, 5068, 5070, 5072, 5074, 5076, 5077, 5078, 5079,
|
||||
5080, 5081, 5082, 5083, 5084, 5085, 5086, 50860, 5087, 5088,
|
||||
6001, 6067, 8001, 8002, 8003, 8018, 8032, 8035, 8040, 8046,
|
||||
8051, 8056, 8061, 8067, N5001
|
||||
```
|
||||
|
||||
`8010`과 `8086`은 활성 cue alias가 아니므로 넣지 않는다. 승인 Cuts에 종속 asset이 없는
|
||||
장면은 allowlist에 있더라도 기존 asset 검증에서 계속 차단된다.
|
||||
|
||||
## 프로세스 범위 적용 순서
|
||||
|
||||
엄격한 파일 검사가 끝난 뒤 다음 값을 process scope에만 적용한다.
|
||||
|
||||
1. 승인된 native SHA-256 pin
|
||||
2. 승인된 Interop SHA-256 pin
|
||||
3. `MBN_STOCK_PLAYOUT_MODE=Live`
|
||||
4. Live authorization — 항상 마지막에 설정
|
||||
|
||||
중간 환경 쓰기가 실패하면 기존 값을 복구하고 Live authorization을 새로 설정하지 않는다.
|
||||
`EnvironmentLiveAuthorization`은 `MainWindow`와 `IPlayoutEngine`을 만들 때 값을 한 번만
|
||||
캡처하므로, 부트스트랩은 반드시 `new MainWindow()`보다 먼저 실행된다.
|
||||
|
||||
Release 빌드에서는 `--development-live`가 전달되어도 로컬 승인 파일을 읽지 않고 환경을
|
||||
변경하지 않는다. 이 개발 편의 경로는 기존 운영 Live 승인 경로나 안전 게이트를 대체하지
|
||||
않는다.
|
||||
212
docs/LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md
Normal file
212
docs/LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md
Normal file
@@ -0,0 +1,212 @@
|
||||
# 원본 WinForms Designer 이벤트 동등성 감사
|
||||
|
||||
감사 기준일은 2026-07-15이다. 원본 `C:\Users\MD\source\repos\MBN_STOCK_N`의 커밋
|
||||
`309286309eaf20b58172247263f575753a860700`을 읽기 전용으로 조사했다. 대상은 실제로
|
||||
Designer가 구독하는 이벤트이며, 선언만 있고 구독되지 않은 메서드는 수에 넣지 않았다.
|
||||
|
||||
Designer 구독은 186개이고, 같은 핸들러를 여러 컨트롤에 연결한 구독을 화면별로 합치면
|
||||
171개다. 이 문서의 상세 목록은 그 171개를 한 번씩 모두 분류한다.
|
||||
|
||||
## 분류 기준
|
||||
|
||||
- `IMPL`: 원본의 활성 업무 동작이 C# 소유 상태/워크플로, 엄격한 WebView 브리지 intent,
|
||||
또는 네이티브 playout 경로로 이관됐다.
|
||||
- `DEAD`: 원본 메서드가 비어 있거나 전부 주석이거나 즉시 반환한다. 새 명령을 만들지 않는
|
||||
것이 원본과 같다.
|
||||
- `VISUAL`: WinForms 전용 paint/draw/focus/resize 동작이며 DOM, CSS, 브라우저 기본 동작으로
|
||||
대체됐다.
|
||||
- `DRAG`: 원본 drag/mouse 순서를 Web drag-and-drop과 C# 소유 순서 변경으로 이관한 묶음이다.
|
||||
- `SAFETY`: 원본과 의도적으로 다르다. 기존 송출 안전 정책 때문에 자동 `StopAll`을 넣지 않는다.
|
||||
|
||||
## 집계
|
||||
|
||||
| 화면 | Designer 구독 | 고유 핸들러 | IMPL | DEAD | VISUAL | DRAG | SAFETY |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|
|
||||
| UC1 | 9 | 9 | 3 | 2 | 4 | 0 | 0 |
|
||||
| UC2 | 4 | 4 | 3 | 1 | 0 | 0 | 0 |
|
||||
| UC3 | 18 | 18 | 14 | 4 | 0 | 0 | 0 |
|
||||
| UC4 | 15 | 15 | 13 | 2 | 0 | 0 | 0 |
|
||||
| UC5 | 20 | 9 | 6 | 3 | 0 | 0 | 0 |
|
||||
| UC6 | 13 | 13 | 12 | 1 | 0 | 0 | 0 |
|
||||
| UC7 | 7 | 6 | 5 | 1 | 0 | 0 | 0 |
|
||||
| AList | 3 | 3 | 3 | 0 | 0 | 0 | 0 |
|
||||
| EList | 3 | 3 | 3 | 0 | 0 | 0 | 0 |
|
||||
| FSell | 3 | 3 | 3 | 0 | 0 | 0 | 0 |
|
||||
| GraphE | 15 | 15 | 14 | 1 | 0 | 0 | 0 |
|
||||
| PList | 7 | 7 | 6 | 1 | 0 | 0 | 0 |
|
||||
| ThemeA | 13 | 13 | 12 | 1 | 0 | 0 | 0 |
|
||||
| VIList | 10 | 10 | 10 | 0 | 0 | 0 | 0 |
|
||||
| MainForm | 46 | 43 | 24 | 3 | 6 | 9 | 1 |
|
||||
| **합계** | **186** | **171** | **131** | **20** | **10** | **9** | **1** |
|
||||
|
||||
UC5는 20개 구독이 9개 핸들러를, UC7은 7개 구독이 6개 핸들러를, MainForm은
|
||||
46개 구독이 43개 핸들러를 공유한다. 따라서 구독 수와 고유 핸들러 수가 다르다.
|
||||
|
||||
## 171개 핸들러 상세 증거
|
||||
|
||||
`@숫자`는 각 원본 `*.Designer.cs`의 이벤트 구독 줄이다.
|
||||
|
||||
### UC1 — `Control/UC1.Designer.cs`
|
||||
|
||||
- `IMPL (3)`: `treeView_DoubleClick@51`, `chE_CheckedChanged@73`, `UC1_Load@84`
|
||||
- `DEAD (2)`: `treeView_BeforeSelect@49`, `treeView_AfterSelect@50`
|
||||
- `VISUAL (4)`: `treeView_BeforeCollapse@46`, `treeView_BeforeExpand@47`,
|
||||
`treeView_DrawNode@48`, `treeView_MouseDown@52`
|
||||
|
||||
### UC2 — `Control/UC2.Designer.cs`
|
||||
|
||||
- `IMPL (3)`: `btnswap_Click@75`, `listbox_DoubleClick@106`, `UC2_Load@126`
|
||||
- `DEAD (1)`: `listbox_SelectedIndexChanged@105`
|
||||
|
||||
### UC3 — `Control/UC3.Designer.cs`
|
||||
|
||||
- `IMPL (14)`: `btnswap_Click@154`, `txtSearch_KeyPress@220`, `listBox_DoubleClick@232`,
|
||||
`btnsearch_Click@249`, `txtj_KeyPress@314`, `btnsearch2_Click@328`,
|
||||
`FpSpread2_CellDoubleClick@396`, `btnAdd_Click@470`, `btn4_Click@531`,
|
||||
`btn3_Click@545`, `btn2_Click@559`, `btn1_Click@573`, `listBox1_DoubleClick@720`,
|
||||
`UC3_Load@741`
|
||||
- `DEAD (4)`: `txtSearch_KeyDown@219`, `listBox_SelectedIndexChanged@231`,
|
||||
`FpSpread2_CellClick_1@395`, `FpSpread_CellClick@641`
|
||||
|
||||
### UC4 — `Control/UC4.Designer.cs`
|
||||
|
||||
- `IMPL (13)`: `btn1_Click@288`, `txts_KeyDown@297`, `btn2_Click@311`,
|
||||
`btn3_Click@325`, `btn4_Click@339`, `FpSpread1_CellClick@406`,
|
||||
`FpSpread1_CellDoubleClick@407`, `btnpre_Click@483`, `btnnow_Click@497`,
|
||||
`timer1_Tick@659`, `btnnow_6_Click@673`, `btnnow_12_Click@687`, `UC4_Load@752`
|
||||
- `DEAD (2)`: `FpSpread1_DoubleClick@408`, `FpSpread2_CellClick@564`
|
||||
|
||||
### UC5 — `Control/UC5.Designer.cs`
|
||||
|
||||
- `IMPL (6)`: `btn1_Click@497`, `btnsearch2_Click@571`, `txtj_KeyPress@581`,
|
||||
`btnsearch1_Click@747`, `txts_KeyPress@757`, `UC5_Load@1007`
|
||||
- `DEAD (3)`: `txtj_TextChanged@580`, `txts_TextChanged@756`, `FpSpread_CellClick@939`
|
||||
|
||||
### UC6 — `Control/UC6.Designer.cs`
|
||||
|
||||
- `IMPL (12)`: `btlistadd_Click@263`, `txtSearch_KeyPress@284`,
|
||||
`listBox_DoubleClick@295`, `btnsearch_Click@312`, `btnsave_Click@365`,
|
||||
`btndel_Click@379`, `FpSpread1_CellClick@456`, `FpSpread2_CellClick@570`,
|
||||
`FpSpread2_KeyDown@571`, `btnDelete_Click@648`, `btnAdd_Click@662`, `UC6_Load@673`
|
||||
- `DEAD (1)`: `tabp6_1_Paint@331`
|
||||
- 이벤트 구독과 별도로 원본 `FpSpread2.AllowDragDrop = true`가
|
||||
`Control/UC6.Designer.cs:519`에 있다. 이는 `DRAG` 경로의 전문가 추천행 재정렬로 이관한다.
|
||||
|
||||
### UC7 — `Control/UC7.Designer.cs`
|
||||
|
||||
- `IMPL (5)`: `btnsearch_Click@185`, `txts_KeyPress@194`, `btn4_Click@219`,
|
||||
`FpSpread1_CellClick@301`, `UC7_Load@369`
|
||||
- `DEAD (1)`: `groupBox3_Enter@161`
|
||||
|
||||
### AList — `Form/AList.Designer.cs`
|
||||
|
||||
- `IMPL (3)`: `btnok_Click@64`, `btncn_Click@88`, `AList_Load@124`
|
||||
|
||||
### EList — `Form/EList.Designer.cs`
|
||||
|
||||
- `IMPL (3)`: `btncn_Click@56`, `btnok_Click@82`, `EList_Load@137`
|
||||
|
||||
### FSell — `Form/FSell.Designer.cs`
|
||||
|
||||
- `IMPL (3)`: `btncn_Click@109`, `btnok_Click@125`, `FSell_Load@337`
|
||||
|
||||
### GraphE — `Form/GraphE.Designer.cs`
|
||||
|
||||
- `IMPL (14)`: `upSearch_Click@220`, `txt1_KeyPress@229`, `downSearch_Click@244`,
|
||||
`FpSpread1_CellClick@312`, `FpSpread1_CellDoubleClick@313`, `btndel_Click@402`,
|
||||
`btnall_Click@417`, `btnAdd_Click@432`, `txtSearch_KeyPress@453`,
|
||||
`listBox_DoubleClick@464`, `btnsearch_Click@481`, `btadd_Click@531`,
|
||||
`btnok_Click@1274`, `GraphE_Load@1318`
|
||||
- `DEAD (1)`: `GraphE_KeyPress@1319`
|
||||
|
||||
### PList — `Form/PList.Designer.cs`
|
||||
|
||||
- `IMPL (6)`: `btnadd_Click@55`, `listBox_DoubleClick@79`, `btncn_Click@95`,
|
||||
`button3_Click@111`, `button1_Click@127`, `PList_Load@139`
|
||||
- `DEAD (1)`: `listBox_SelectedIndexChanged@78`
|
||||
|
||||
### ThemeA — `Form/ThemeA.Designer.cs`
|
||||
|
||||
- `IMPL (12)`: `btncancel_Click@246`, `btnok_Click@260`, `FpSpread_KeyDown@353`,
|
||||
`btn4_Click@422`, `btn3_Click@436`, `btn2_Click@450`, `btn1_Click@464`,
|
||||
`btnC_Click@479`, `listBox_DoubleClick@521`, `txtSearch_KeyPress@530`,
|
||||
`btnsearch_Click@547`, `Theme_Load@569`
|
||||
- `DEAD (1)`: `listBox_SelectedIndexChanged@520`
|
||||
|
||||
### VIList — `Form/VIList.Designer.cs`
|
||||
|
||||
- `IMPL (10)`: `txtSearch_KeyPress@188`, `btnok_Click@202`, `btn4_Click@391`,
|
||||
`btn3_Click@405`, `btn2_Click@419`, `btn1_Click@433`, `listBox_DoubleClick@456`,
|
||||
`btnsearch_Click@473`, `btncancel_Click@487`, `VILIST_Load@528`
|
||||
|
||||
### MainForm — `MainForm.Designer.cs`
|
||||
|
||||
- `IMPL (24)`: `tabControl1_SelectedIndexChanged@1062`, `btnPrepare_Click@1465`,
|
||||
`PlayList_CellClick@1723`, `PlayList_KeyPress@1726`, `ckback_CheckedChanged@1818`,
|
||||
`btnback_Click@1854`, `btntdelete_Click@1869`, `btndelete_Click@1884`,
|
||||
`btnload_Click@1899`, `button5_Click@1914`, `btndown_Click@1930`, `btnup_Click@1946`,
|
||||
`checkBox1_CheckedChanged@1986`, `btnTake_Click@2018`, `txtSearch_KeyPress@2047`,
|
||||
`b1_Click@2108`, `button9_Click@2207`, `btnNext_Click@2410`,
|
||||
`btnTakeout_Click@2428`, `timer1_Tick@2433`, `timer3_Tick@2443`,
|
||||
`Form1_Load@2470`, `MainForm_KeyDown@2472`, `MainForm_KeyUp@2473`
|
||||
- `DEAD (3)`: `PlayList_LeaveCell@1722`, `GridView1_RowLeave@2081`,
|
||||
`FpSpread2_CellDoubleClick@2280`
|
||||
- `VISUAL (6)`: `panel6_Paint@1426`, `GridView1_CellEnter@2080`,
|
||||
`listBox_DrawItem@2189`, `timer2_Tick@2438`, `MainForm_Paint@2471`,
|
||||
`MainForm_Resize@2474`
|
||||
- `DRAG (9)`: `tab_DragOver@1063`, `tab_MouseDown@1064`, `tab_MouseMove@1065`,
|
||||
`tab_MouseUp@1066`, `PlayList_DragDrop@1724`, `PlayList_DragOver@1725`,
|
||||
`listView1_MouseDown@2349`, `listView1_MouseMove@2350`, `listView1_MouseUp@2351`
|
||||
- `SAFETY (1)`: `MainForm_FormClosing@2469`
|
||||
|
||||
## ThemeA `중복확인` 동등성
|
||||
|
||||
원본 `Form/ThemeA.cs:84-109`는 입력 이름과 현재 KRX/NXT 선택을 기준으로 정확히 같은
|
||||
테마명을 조회하고 `이미 사용중인 테마명입니다.` 또는 `사용 가능한 테마명입니다.`를 표시한다.
|
||||
새 구현은 다음 경로를 사용한다.
|
||||
|
||||
1. `Web/index.html`의 `operator-catalog-name-check`가 원본 `중복확인` 버튼이다.
|
||||
2. Web은 이름만 담은 `check-operator-catalog-theme-name` intent를 보낸다. market, code,
|
||||
table 이름 같은 DB 권한 정보는 보내지 못한다.
|
||||
3. `LegacyBridgeProtocol`이 닫힌 payload와 128자 canonical text를 검증한다.
|
||||
4. `LegacyOperatorController.CheckOperatorCatalogThemeNameAsync`가
|
||||
`LegacyOperatorCatalogWorkflowController.CheckThemeNameAvailabilityAsync`를 호출한다.
|
||||
5. 워크플로는 C#이 소유한 현재 KRX/NXT 대상과 exact title을
|
||||
`IThemeCatalogPersistenceService.ThemeNameExistsAsync`에 전달한다. 구현은 선택한 provider의
|
||||
`SB_LIST`에 parameterized `COUNT(*)` SELECT를 정확히 한 번 실행하며 mutation executor를
|
||||
호출하지 않는다. 128자 테마명도 잘림 없는 exact query로 처리한다.
|
||||
6. 조회 결과를 확정할 수 없으면 `Indeterminate`로 표시하며 DB 쓰기를 하지 않는다.
|
||||
|
||||
원본 쿼리는 edit 중인 현재 `SB_CODE`를 제외하지 않는다. 따라서 제목을 바꾸지 않은 기존
|
||||
테마에서 `중복확인`을 누르면 자기 행 때문에 `이미 사용중인 테마명입니다.`가 표시된다. 새 구현도
|
||||
고객의 원본 우선 요구에 따라 KRX/NXT 모두 이 동작을 그대로 보존한다.
|
||||
|
||||
검증은 `LegacyThemeCatalogPersistenceServiceTests`, `LegacyOperatorCatalogWorkflowTests`,
|
||||
`LegacyOperatorCatalogBridgeTests`, `LegacyOperatorCatalogParityWebTests`에 있다.
|
||||
KRX와 NXT의 같은 이름을 서로 혼동하지 않는지,
|
||||
create의 중복/사용 가능, edit의 자기 행 중복, 128자 parameter binding, 결과 불명 상태,
|
||||
엄격한 payload, Web 버튼 및 native dispatch를 확인한다.
|
||||
|
||||
## 의도적인 종료 안전 차이
|
||||
|
||||
원본 `MainForm.cs:751-780`은 종료 확인 뒤 `KAScenePlayer.StopAll()`, `KAScene.Unload()`,
|
||||
500ms 대기, 현재 프로세스 강제 종료를 수행한다. 새 앱은 이를 그대로 이관하지 않는다.
|
||||
|
||||
- `MainWindow.CloseConfirmation.cs:88-119`는 PREPARED/PROGRAM, pending callback,
|
||||
`OutcomeUnknown`을 사용자에게 명시하고 종료 과정에서 TAKE OUT을 자동 실행하지 않는다.
|
||||
- `MainWindow.Playout.cs:778-823`은 on-air 장면, pending callback, quarantine,
|
||||
`OutcomeUnknown`이 없을 때만 bounded disconnect를 시도한다.
|
||||
- 이 차이는 기존 안전 게이트의 `결과 불명 시 반복 금지`와 `명시적 송출 명령` 정책을 지키기 위한
|
||||
활성 안전 요구사항이다. 동등성 작업에서 완화하거나 자동 `StopAll`로 바꾸지 않는다.
|
||||
|
||||
## 기타 감사 메모
|
||||
|
||||
- 원본 `MainForm.Designer.cs:1399`에서 PREPARE가 들어 있는 `panel3.Visible = false`다.
|
||||
새 Web UI도 PREPARE를 일반 조작 화면에서는 숨기고 네이티브/승인된 검증 경로는 유지한다.
|
||||
- 원본의 단일 인스턴스 기대는 `LegacyParityApp/App.xaml.cs`의
|
||||
`AppInstance.FindOrRegisterForKey`로 구현됐다.
|
||||
- 원본 `timer3_Tick`의 Tornado 상태 감시는 `IPlayoutEngine` 뒤의
|
||||
`TornadoPlayoutEngine` monitor/reconnect 상태 기계로 격리돼 있다.
|
||||
- 이벤트 이름이 여러 화면에서 같더라도 화면별 메서드는 별개로 셌다. 예를 들어
|
||||
`btn1_Click`, `btnsearch_Click`, `listBox_DoubleClick`은 전역 이름 하나가 아니라 각 화면의
|
||||
서로 다른 바인딩이다.
|
||||
@@ -13,15 +13,19 @@
|
||||
WebView2에 표시하는 x64 Windows 데스크톱/MSIX 앱이다.
|
||||
|
||||
초기 프로토타입 문서의 “미이관 버튼 disabled”, “Tornado2에 연결하지 않음”, “DB write
|
||||
없음”은 현재 상태가 아니다. 원본 UI와 클릭 이벤트는 LegacyParityApp → strict bridge →
|
||||
C# workflow로 연결됐고, 개발 DB write 9개 시나리오와 설치된 MSIX의 개발 PGM 최종
|
||||
통합까지 검증했다. 기본 송출 모드는 계속 `DryRun`이다.
|
||||
없음”은 현재 구현 상태가 아니다. 원본 UI 이벤트는 LegacyParityApp → strict bridge →
|
||||
C# workflow로 연결되고 개발 DB write 9개 시나리오의 기존 증적도 있다. 다만 현재 병렬
|
||||
변경이 합쳐진 signed Release MSIX 설치·DryRun 실행, 실제 마우스/CDP UI와 제한된
|
||||
HELLO/BYE 연결은 2026-07-15에 확인했다. scene/PREPARE/TAKE/PGM은 실행하지 않았으므로
|
||||
전체 방송 송출 성공으로 판정하지 않는다. 기본 송출 모드는 계속 `DryRun`이다.
|
||||
|
||||
## 상태 정의
|
||||
|
||||
| 상태 | 의미 |
|
||||
|---|---|
|
||||
| `완료` | 현재 LegacyParityApp 코드와 해당 자동/통합 검증에 반영됨 |
|
||||
| `완료` | 현재 LegacyParityApp 코드와 표에 명시한 자동/통합 검증에 반영됨. package/Live 여부는 각 행의 증적 범위로 별도 판정 |
|
||||
| `부분 실측` | 현재 package 또는 Live의 표에 명시한 범위만 실제 확인했으며 scene/PGM 전체 통합으로 확대할 수 없음 |
|
||||
| `현재 빌드 실측 제외` | 구현 경로는 있으나 현재 병렬 변경을 합친 package-context/CDP/PGM 결과를 아직 이 감사의 성공 증거로 채택하지 않음 |
|
||||
| `외부자산 필요` | 코드로 만들 수 없는 Git/MSIX 밖의 승인 영상·배경이 제공되지 않음 |
|
||||
| `외부 데이터 정합성` | 현재 DB view/data가 원본 규칙의 fresh identity를 공급하지 않아 추정 없이 차단함 |
|
||||
|
||||
@@ -33,25 +37,61 @@ C# workflow로 연결됐고, 개발 DB write 9개 시나리오와 설치된 MSIX
|
||||
| LF-002 | P0 | cut/asset coverage | 완료 | active alias 45개 `.t2s` 존재. alias missing/unsafe 0, asset unsafe 0, asset missing 14를 분리 보고 | 누락 자산 자체는 LF-001/LF-003 |
|
||||
| LF-003 | P0 | `s5006` 큐브 배경 | 외부자산 필요 | `Video\큐브배경.vrv` 1개가 승인 Cuts에 없음. builder 누락이 아님 | 제공 후 s5006 DryRun/PGM |
|
||||
| LF-004 | P0 | 실제 개발 DB write | 완료 | GraphE 4 + PList/AList 2 + ThemeA KRX/NXT 2 + EList 1, 총 9개가 create/save→fresh readback→delete→absence PASS, 잔여 0 | 운영 DB write를 뜻하지 않음 |
|
||||
| LF-005 | P0 | 개발 Tornado2/PGM 최종 통합 | 완료 | 설치된 최신 MSIX에서 `5001` PREPARE/TAKE IN/자동 갱신 → playlist NEXT `5074` 1/2 → Page NEXT 2/2 → TAKE OUT, Network Monitoring·PGM·BYE 확인 | 14개 외부 영상 자산 scene은 제공 후 별도 PGM |
|
||||
| LF-005 | P0 | 개발 Tornado2/PGM 최종 통합 | 부분 실측 | 현재 signed Release 설치·DryRun 실행과 실제 UI를 확인. 별도 Live에서 HELLO request/success 각 1회와 BYE 1회만 확인했고 scene/PREPARE/TAKE/DB write는 0 | scene PREPARE/TAKE/PGM 전체 통합과 14개 외부 영상 자산 scene은 별도 |
|
||||
| LF-006 | P0 | 원본 35 scene | 완료 | 원본 inventory와 source 기준선 35/35, DTO→mutation→runtime matrix 통과 | 모든 scene의 실제 PGM 완료로 확대 해석 금지 |
|
||||
| LF-007 | P0 | PageN/NEXT | 완료 | 5·6·12개 단위, 최대 20페이지, 빈/경계/마지막 부분 페이지 테스트와 개발 PGM에서 `5074` 9종목의 5+4 Page NEXT·다음 행 NEXT 확인 | 없음 |
|
||||
| LF-007 | P0 | PageN/NEXT | 완료 | 5·6·12개 단위, 최대 20페이지, 빈/경계/마지막 부분 페이지와 같은 scene/다음 행 구분을 자동 테스트로 검증 | 현재 package/PGM 실측은 LF-005와 함께 판정 |
|
||||
| LF-008 | P0 | 원클릭 TAKE IN | 완료 | 보이는 TAKE IN/F8 한 번으로 fresh page load 후 PREPARE 1회→TAKE IN 1회. native PREPARE는 진단용으로 유지하되 hidden | unknown에서 재시도 금지 |
|
||||
| LF-009 | P0 | C# 권위/strict bridge | 완료 | Web은 intent만 전송. `LegacyBridgeProtocol` allowlist와 `LegacyOperatorController` snapshot이 DB identity·playlist·scene·송출 상태의 권위 | 새 intent에도 동일 경계 유지 |
|
||||
| LF-010 | P1 | 10개 탭과 action inventory | 완료 | 10탭, fixed 328, 업종 44, 종목 31, 비교 target 24/action 9를 폐쇄형으로 고정 | 동적 DB 행은 별도 검증 |
|
||||
| LF-011 | P1 | UC4/UC6/UC7 클릭 | 완료 | 테마·전문가·거래정지는 원본 단일 클릭. UC4/UC6 행은 fixed tree handler와 독립, stale generation 거부 | 없음 |
|
||||
| LF-012 | P1 | GraphE/FSell/VI | 완료 | GraphE CRUD·찾기·정렬·행 double-click, FSell/VI 확인 시 save+playlist append+close, 취소 경계 이관 | s5025/VI 전용 PGM은 LF-005 |
|
||||
| LF-013 | P1 | PList/AList | 완료 | 목록·생성·save/load/delete·행 double-click 이관, 개발 DB write/readback/cleanup PASS | 기존 blocked raw row는 추정 복원 금지 |
|
||||
| LF-014 | P1 | ThemeA/EList | 완료 | 검색·신규·편집·삭제·종목 구성·순서·Delete key 이관, KRX/NXT/expert 개발 DB 시나리오 PASS | scene PGM은 LF-005 |
|
||||
| LF-014 | P1 | ThemeA/EList | 완료 | 검색·신규·편집·삭제·종목 구성·Delete key, ThemeA exact-title 중복확인, EList opaque `rowId` drag 재정렬 이관. 실제 UI에서 ThemeA 500건 중복 read와 EList 5행 reorder 확인 | scene PGM은 LF-005 |
|
||||
| LF-015 | P1 | UC5 해외 | 완료 | 해외업종·해외종목·해외지수 조회와 playlist 경로 이관 | s6001 13개 영상은 LF-001 |
|
||||
| LF-016 | P1 | F2/F3 기본 배경 | 외부자산 필요 | sibling background root, picker, background-none와 trusted path 검사는 완료. 이 장비에 `기본.vrv`가 없음 | 제공 전 fail closed |
|
||||
| LF-017 | P1 | 시스템 종료 확인 | 완료 | package-context에서 기본 취소 확인창의 중립 문구·종료/취소 두 버튼을 대조하고 종료 1회, BYE 1회, 자동 TAKE OUT/반대 명령 없음 확인 | 없음 |
|
||||
| LF-017 | P1 | 시스템 종료 확인 | 완료 | 기본 취소 확인창, 중립 문구, 종료/취소 두 버튼과 자동 TAKE OUT/반대 명령 금지 경계를 코드·자동 테스트로 유지 | 현재 Release package-context 회귀는 LF-005와 함께 판정 |
|
||||
| LF-018 | P1 | 원본 비교쌍/수동 파일 | 완료 | `종목비교.dat` 8쌍 1회 import·재시작 marker, FSell 3×5행과 VI 9항목 trusted parser/store 검증 | 원본 파일은 계속 읽기 전용 |
|
||||
| LF-019 | P1 | 실제 DB read→DTO→mutation | 완료 | Oracle/MariaDB 필수 scene selector 33/33, 전체 query 58건 PASS | 외부 asset/PGM 성공과 별도 |
|
||||
| LF-020 | P2 | FarPoint 대체 | 완료 | Web table로 바꾸되 선택·정렬·이동·single/double-click·저장 이벤트를 strict C# intent로 재현 | 활성 Print/Excel export는 원본에도 없음 |
|
||||
| LF-020 | P2 | FarPoint 대체 | 완료 | 실제 마우스로 playlist 다중행 reorder·checkbox 차단·탭 release 전 dragover 교환·EList reorder 확인. row drop 버블링의 cut append와 Chromium checkbox-origin target 문제를 수정하고 DOM 회귀로 고정 | 활성 Print/Excel export는 원본에도 없음 |
|
||||
| LF-021 | P2 | 패키지 단일 인스턴스·모달 격리 | 완료 | 두 번째 activation 전달, 강제 종료 없음. modal에서 F2/F3/F8/Escape와 playlist key 격리 | 새 MSIX 전체 회귀 |
|
||||
| LF-022 | P2 | 영구 운영 로그/bridge 오류 | 완료 | bounded/redacted log와 toast, malformed payload가 송출 상태를 바꾸지 않음 | authoritative Network Monitoring과 함께 판독 |
|
||||
| LF-023 | P1 | NXT 저장 playlist restore | 외부 데이터 정합성 | stale code를 제목/current identity로 재검증하는 닫힌 경로는 완료. 현재 `v_all_stock` 결과가 비어 preview를 fail closed | DBA/data 정합성 없이는 direct-table 추정 금지 |
|
||||
| LF-024 | P0 | Designer 이벤트 전수 감사 | 완료 | 원본 Designer 구독 **186개**, 화면별 고유 핸들러 **171개**를 IMPL 131/DEAD 20/VISUAL 10/DRAG 9/SAFETY 1로 전수 분류 | 상세 줄 단위 근거는 `LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md` |
|
||||
| LF-025 | P0 | VS Development Live 시작 구성 | 완료 | `.slnLaunch`와 패키지 프로필이 LegacyParityApp을 시작 대상으로 고정. 실제 Release에서 `--development-live`가 무시돼 DryRun, TCP/Network 변경 0임을 확인 | Live는 exact argument + Debug + strict local authorization을 계속 요구 |
|
||||
|
||||
## 이벤트·drag 감사 상세
|
||||
|
||||
[`LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md`](LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md)는 원본
|
||||
커밋의 `*.Designer.cs`를 읽기 전용으로 조사해 186개 구독과 171개 고유 핸들러를 줄 단위로
|
||||
대조한다. 선언만 있고 구독하지 않는 메서드는 제외하며, `DEAD`/`VISUAL`은 새 활성 업무
|
||||
intent를 만들지 않는 것이 원본과 동등하다. 종료의 자동 `StopAll`만 기존 안전 정책 때문에
|
||||
의도적으로 이관하지 않는 `SAFETY` 항목이다.
|
||||
|
||||
현재 `DRAG` 구현은 다음 세 C# 권위 경로를 포함한다.
|
||||
|
||||
- playlist 행 drag는 선택된 비연속 행도 현재 표시 순서를 보존한 한 블록으로 임의
|
||||
before/after 위치에 옮긴다. 체크박스에서 시작한 drag와 PREPARED/PROGRAM/pending/unknown
|
||||
상태의 변경은 차단한다.
|
||||
- 시장 탭은 drop 때가 아니라 dragover 대상에 들어갈 때 교환한다. source/target identity와
|
||||
예상 두 인덱스가 C# 현재 순서와 일치할 때만 적용해 중복 메시지가 순서를 되돌리지 않는다.
|
||||
- 원본 UC6 `FpSpread2.AllowDragDrop`은 ThemeA/EList 편집행의 opaque `rowId` drag로
|
||||
이관했다. Web은 play index나 DB identity를 결정하지 않는다.
|
||||
|
||||
ThemeA의 원본 `중복확인`도 이름만 담은 strict intent로 연결했다. C#이 현재 KRX/NXT를
|
||||
결정하고 선택 provider의 `SB_LIST`에 exact title parameterized read를 한 번 수행한다.
|
||||
결과 불명은 `Indeterminate`이며 write나 추정 fallback이 없다. 원본처럼 edit 자기 행을
|
||||
제외하지 않아 변경하지 않은 이름은 중복으로 판정된다.
|
||||
|
||||
## Development Live strict local authorization
|
||||
|
||||
[`DEVELOPMENT_LIVE_VISUAL_STUDIO.md`](DEVELOPMENT_LIVE_VISUAL_STUDIO.md)의 시작 구성은
|
||||
정확한 `--development-live` 인자와 Debug 빌드에서만 Git 제외 로컬 승인 파일을 읽는다.
|
||||
승인 파일은 `%LOCALAPPDATA%` 아래에서 reparse가 아닌 경로, 최대 4096바이트, 정확한 다섯
|
||||
속성, canonical JSON, exact authorization 문자열과 독립 승인된 native/Interop SHA-256을
|
||||
모두 만족해야 한다. Live authorization은 환경 설정의 마지막 단계이며 일부 적용 실패 시
|
||||
기존 값을 복구한다. Release, 인자 불일치, 파일 없음/오류/알 수 없는 속성은 Live를 구성하지
|
||||
않는다. 기존 `trustedLiveOutputEnabled`, alias allowlist, asset 검사와 송출 안전 게이트는
|
||||
그대로 중첩된다.
|
||||
|
||||
## DB 검증 상세
|
||||
|
||||
@@ -133,17 +173,12 @@ redacted 형태로 보고한다.
|
||||
|
||||
## 최종 증적 기록
|
||||
|
||||
확정된 증적과 최신 전체 회귀의 기록 위치는
|
||||
[`LEGACY_PARITY_VALIDATION_20260715.md`](LEGACY_PARITY_VALIDATION_20260715.md)다.
|
||||
|
||||
다음 값은 추측하거나 이전 package 결과를 재사용하지 않는다.
|
||||
|
||||
| 항목 | 상태 |
|
||||
|---|---|
|
||||
| Debug/Release x64 전체 테스트 개수 | **PASS** — .NET 각 2,394/2,394, Web 435/435 |
|
||||
| 새 Release x64 MSIX SHA-256·서명 | `FC4EEE1509675E643D2B4CB435E279CAC4611B28534048D9B9EE611E361E0E1F`, Valid, `CN=Comtrophy` |
|
||||
| 새 package-context 실행 | **PASS** — DryRun과 개발 Live, 정상 종료 |
|
||||
| 개발 Tornado2 Network Monitoring/PGM 결과 | **PASS** — `5001` → `5074` 1/2 → 2/2 → TAKE OUT/BYE |
|
||||
| Gitea 반영 commit | **PASS** — 최종 이관·검증 문서 포함 commit을 `origin/main`에 fast-forward push |
|
||||
현재 구현 증적과 최종 검증 범위는
|
||||
[`LEGACY_PARITY_VALIDATION_20260715.md`](LEGACY_PARITY_VALIDATION_20260715.md)에 기록한다.
|
||||
병렬 변경을 모두 합친 .NET Debug/Release x64는 각각 2,446/2,446, Web Node는 438/438이며
|
||||
Visual Studio 2026 Debug/Release x64 빌드는 경고 0·오류 0이다. 새 signed Release x64 MSIX의
|
||||
hash·서명·설치 실행, 실제 CDP UI와 제한된 HELLO/BYE 결과도 현재 값으로 기록했다. 단,
|
||||
scene/PREPARE/TAKE/PGM을 실행하지 않은 현재 연결 회차를 전체 방송 송출 성공으로 확대하지
|
||||
않으며 과거 package hash나 PGM 로그를 현재 결과로 재사용하지 않는다.
|
||||
|
||||
원본 저장소는 최종 검증과 배포 이후에도 계속 읽기 전용으로 유지한다.
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
# LegacyParityApp 이관 검증 증적 — 2026-07-15
|
||||
|
||||
이 문서는 현재 `MBN_STOCK_WEBVIEW.LegacyParityApp`의 구현·통합 최종 검증 결과를
|
||||
한곳에 모은다. 원본
|
||||
이 문서는 현재 `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`은 모든 조사와 테스트에서 읽기 전용으로
|
||||
취급했다.
|
||||
|
||||
@@ -15,23 +18,79 @@
|
||||
| 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로 연결 |
|
||||
| 전용 입력 | GraphE, FSell, VI, PList, AList, ThemeA, EList를 WebView 화면과 C# intent로 연결; ThemeA exact-title 중복확인 포함 |
|
||||
| 해외 | UC5 해외업종·해외종목·해외지수 조회와 playlist 생성 |
|
||||
| playlist | 단일/Ctrl/Shift 선택, enabled, 위/아래, 선택/전체 삭제, drag/batch 경계 |
|
||||
| FarPoint 대체 | Web table로 표현하되 원본 클릭·더블클릭·정렬·이동·저장 이벤트 의미 유지 |
|
||||
| playlist | 단일/Ctrl/Shift 선택, enabled, 위/아래, 선택/전체 삭제와 비연속 다중 선택 block drag; PREPARED/PROGRAM/pending/unknown 변경 차단 |
|
||||
| FarPoint 대체 | Web table로 표현하되 원본 클릭·더블클릭·정렬·이동·저장, 탭 dragover 교환과 UC6/EList opaque 행 drag 의미 유지 |
|
||||
|
||||
상세 이벤트 대조는 [`OPERATOR_UI_PARITY.md`](OPERATOR_UI_PARITY.md)를 따른다.
|
||||
|
||||
### 이벤트·drag·중복확인 구현 증적
|
||||
|
||||
줄 단위 원본 근거는
|
||||
[`LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md`](LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md)에 있다.
|
||||
186개 구독/171개 고유 핸들러 수에는 선언만 있고 구독되지 않은 메서드를 넣지 않았다.
|
||||
|
||||
- playlist drag는 opaque source/target `rowId`와 before/after만 Web에서 보내며, C#이 현재
|
||||
선택 집합을 표시 순서대로 한 블록으로 이동한다. 체크박스 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행을 추가했다.
|
||||
- playlist 여러 행을 실제 마우스로 선택해 한 블록으로 재정렬했고, enabled 체크박스에서
|
||||
시작한 drag는 행 이동을 만들지 않았다.
|
||||
- 시장 탭은 마우스 버튼을 놓기 전 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 형태, 다중 선택 보존, row drop의 ancestor 무시, 외부 text 거부와 exact
|
||||
selected-cut token의 단일 처리를 실제 DOM event 순서로 고정한다.
|
||||
|
||||
### Development Live 시작 구성 증적
|
||||
|
||||
공유 `.slnLaunch`와 package launch profile은 LegacyParityApp을 시작 대상으로 고정한다.
|
||||
[`DEVELOPMENT_LIVE_VISUAL_STUDIO.md`](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 내용도 변하지 않았다.
|
||||
|
||||
## 송출 흐름과 장면
|
||||
|
||||
| 항목 | 결과 |
|
||||
@@ -54,6 +113,7 @@
|
||||
| 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을
|
||||
@@ -71,54 +131,50 @@
|
||||
누락 자산은 Git 또는 MSIX에 임의로 넣지 않는다. 제공되면 같은 trusted-root,
|
||||
0-byte, reparse, root-escape 검사를 통과한 뒤 해당 scene만 다시 검증한다.
|
||||
|
||||
## 개발 Tornado2와 PGM 실측
|
||||
## 2026-07-15 Tornado2 Live 연결 실측
|
||||
|
||||
2026-07-15 개발 Tornado2 `2.7.5.49 x64 DSX10.0 S.R2`의 단일 `30001/tcp`
|
||||
listener와 K3D x64 등록·라이선스를 고정한 뒤, 설치된 MSIX package-context 앱에서 다음
|
||||
시퀀스를 실행했다.
|
||||
아래 시각은 개발 장비 로컬 시간(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건**이다.
|
||||
|
||||
1. 삼성전자 검색 → `5001` playlist 추가
|
||||
2. 원본과 같은 fixed leaf **더블클릭**으로 VI 수동 목록 9종목 조회 → `5074` 2페이지 추가
|
||||
3. `PREPARE 5001 page 1` → `TAKE IN` → `OnScenePlayed` → 자동 갱신 정확히 1회
|
||||
4. `NEXT`로 다음 playlist 항목 `5074 page 1/2` → 자동 갱신 정확히 1회
|
||||
5. 같은 scene `Page NEXT`로 `5074 page 2/2`의 마지막 4종목 송출
|
||||
6. `TAKE OUT All` → `IDLE` → 정상 종료 확인 → `BYE`
|
||||
종료 후 보관한 Network Monitoring 원문은 **300,007자**, SHA-256
|
||||
`45858322F60C135858002EB6243D0474F51F1965E23D2332D397C3A3B5DB8049`다. 이 증적은 현재
|
||||
코드의 Live CONNECT/handshake/DISCONNECT 경로만 확인한다. scene load/mutation,
|
||||
PREPARE, TAKE IN, NEXT/Page NEXT, TAKE OUT 또는 PGM 화면 출력을 검증했다는 뜻이 아니다.
|
||||
|
||||
첫 실측과 화면 증적용 known-outcome 재현은 모두 `OutcomeUnknown=false`로 끝났다. 불명확
|
||||
결과 뒤 명령 재시도는 없었다. Network Monitoring 최종 원문은 1,863줄,
|
||||
299,616문자, SHA-256
|
||||
`7CDB183A2518EF47E5CC3819C2EB14C06492DE0C8E018350A0633E0FBBB5B994`다. 두 실측을
|
||||
합쳐 `LOAD_SCENE` 4/4, `BEGIN_TRANSACTION` 12/12, `VALUE_SET` 258/258,
|
||||
`VISIBLE` 568/568, `SCENE_PREPARE` 12/12, `PLAY` 10/10, `STOPAL` 2/2,
|
||||
`UNLOAD_SCENE` 4/4가 요청/성공으로 일치했고 `SCENE_PLAYED` 10회를 수신했다. 정상
|
||||
종료에서는 `BYE` 요청 1회가 기록됐고 이후 established 연결과 앱/CDP process는 0개다.
|
||||
별도의 Release DryRun 회차에서는 `--development-live`가 무시됐고 TCP 연결이 생성되지
|
||||
않았으며 Network Monitoring 최종 내용도 변하지 않았다. 이는 Debug-only bootstrap 경계를
|
||||
확인한 결과이지 Release Live 송출 결과가 아니다.
|
||||
|
||||
화면 증적은 300프레임 중 72프레임이 검은 기준 화면과 달랐다. `5001` 삼성전자 화면,
|
||||
`5074` page 1의 5종목, page 2의 4종목을 직접 확인했고 TAKE OUT 뒤 기준 검은 화면으로
|
||||
복귀했다. 프레임 원본과 Network Monitoring 원문은 실제 컷·운영자료를 Git에 넣지 않는
|
||||
정책에 따라 로컬 `artifacts/final-validation-20260715`에만 보관한다.
|
||||
## 현재 package와 범위 회귀 기록
|
||||
|
||||
## 최종 전체 회귀 기록
|
||||
|
||||
아래 값은 모든 병렬 변경과 fixed-leaf 더블클릭 회귀 테스트가 합쳐진 뒤 다시 실행한
|
||||
최종값이다.
|
||||
|
||||
| 항목 | 최종 결과 |
|
||||
| 항목 | 2026-07-15 확인 결과 |
|
||||
|---|---|
|
||||
| Debug x64 전체 빌드·테스트 | **PASS** — .NET 2,394/2,394, VS 2026 `ParityDebug|x64`, 경고 0·오류 0 |
|
||||
| Release x64 전체 빌드·테스트 | **PASS** — .NET 2,394/2,394, VS 2026 `Release|x64`, 경고 0·오류 0 |
|
||||
| Web/LegacyParity 전체 테스트 | **PASS** — 47파일, 435/435 (`Test-WebPlayout` 415 + thin-client 20) |
|
||||
| Release x64 MSIX 경로·버전 | `artifacts/final-validation-20260715/package/MBN_STOCK_WEBVIEW.LegacyParityApp_0.1.0.0_x64_Test/MBN_STOCK_WEBVIEW.LegacyParityApp_0.1.0.0_x64.msix`, `0.1.0.0`, 15,200,545 bytes |
|
||||
| 새 MSIX SHA-256·서명 | `FC4EEE1509675E643D2B4CB435E279CAC4611B28534048D9B9EE611E361E0E1F`, **Valid**, `CN=Comtrophy` |
|
||||
| 설치된 package-context 실행 | **PASS** — `Wickedness.MBNStockWebView.LegacyParity_0.1.0.0_x64__qbv3jkvsn3aj0`, DryRun 전체 흐름과 Live 개발 PGM 실행, 정상 종료 |
|
||||
| 개발 Tornado2 Network Monitoring | **PASS** — HELLO, transaction/mutation/query/prepare/play, event, unload, STOPAL, BYE와 연결 해제 확인 |
|
||||
| 개발 PGM PREPARE → TAKE IN → NEXT/Page NEXT → TAKE OUT | **PASS** — `5001` → `5074` 1/2 → `5074` 2/2 → 검은 화면 복귀 |
|
||||
| Gitea main commit/push | **PASS** — 이 최종 검증 문서를 포함한 커밋을 `origin/main`에 fast-forward push |
|
||||
| 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로 확대하지
|
||||
않는다.
|
||||
|
||||
## 판정 경계
|
||||
|
||||
- 35/35 자동 장면 동등성은 모든 장면의 실제 PGM 출력 완료를 뜻하지 않는다.
|
||||
- 33/33 DB selector 통과는 외부 영상/배경 자산 준비를 뜻하지 않는다.
|
||||
- 개발 DB 9개 write 시나리오 통과는 운영 DB에 쓰기를 허용하거나 수행했다는 뜻이 아니다.
|
||||
- 개발 Tornado2/PGM은 안전 게이트를 유지한 별도 통합 검증 대상이다.
|
||||
- 현재 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 외부로 유지한다.
|
||||
|
||||
@@ -28,6 +28,16 @@ playlist, PageN과 송출 상태는 `LegacyOperatorController`의 C# snapshot이
|
||||
- 원본 `Cuts`도 읽기 전용 검증에만 사용하며 수정·복사하지 않는다.
|
||||
- 비밀번호, 라이선스, 벤더 DLL, 인증서, 실제 컷·영상·배경과 로컬 설정은 Git에 넣지 않는다.
|
||||
|
||||
## 원본 Designer 이벤트 전수 감사
|
||||
|
||||
원본 `*.Designer.cs`가 실제로 구독하는 이벤트를 전수 조사한 결과는 **186개 Designer
|
||||
구독, 화면별 중복을 합친 171개 고유 핸들러**다. 선언만 있고 Designer에서 구독하지 않는
|
||||
메서드는 수에 넣지 않았다. 171개는 `IMPL` 131, `DEAD` 20, `VISUAL` 10, `DRAG` 9,
|
||||
`SAFETY` 1로 모두 분류했다. 같은 이름의 핸들러라도 화면이 다르면 별도 바인딩으로 센다.
|
||||
|
||||
상세 원본 파일·구독 줄·분류 근거는
|
||||
[`LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md`](LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md)에 있다.
|
||||
|
||||
## 원본 실행 action inventory
|
||||
|
||||
동적 테마·전문가 DB 행과 전용 편집기의 데이터 행은 아래 고정 수량에 중복해 더하지 않는다.
|
||||
@@ -61,8 +71,8 @@ playlist, PageN과 송출 상태는 `LegacyOperatorController`의 C# snapshot이
|
||||
| VIList | 종목 추가·삭제·이동, 5개 단위 page, 확인 시 저장+추가+닫기 | `LegacyManualListsWorkflow` + trusted store | 원본 형식 read와 격리 write 검증 | `s5074` 전용 입력 PGM 별도 |
|
||||
| PList | 목록, 행 더블클릭 load/save, 확인, 삭제 | `LegacyNamedPlaylistWorkflow` | 개발 DB create/save/read/delete/absence PASS | 복원 항목별 scene PGM 별도 |
|
||||
| AList | 다음 코드와 프로그램명 신규 생성 | named playlist workflow에 통합 | 위 named playlist 시나리오로 PASS | 해당 없음 |
|
||||
| ThemeA | KRX/NXT 테마 생성·편집·삭제, 종목 구성·순서 | `LegacyOperatorCatalogWorkflow` | 개발 DB KRX/NXT 각 1개 PASS | scene PGM 별도 |
|
||||
| EList | 전문가 생성·편집·삭제, 추천 종목·금액·순서 | `LegacyOperatorCatalogWorkflow` | 개발 DB expert 1개 PASS | scene PGM 별도 |
|
||||
| ThemeA | KRX/NXT 테마 생성·편집·삭제, 이름 중복확인, 종목 구성·순서 | `LegacyOperatorCatalogWorkflow` + exact-title 조회 | 개발 DB KRX/NXT 각 1개 PASS | scene PGM 별도 |
|
||||
| EList | 전문가 생성·편집·삭제, 추천 종목·금액·드래그 순서 | `LegacyOperatorCatalogWorkflow` + opaque row reorder | 개발 DB expert 1개 PASS | scene PGM 별도 |
|
||||
|
||||
UC4/UC6의 결과 행은 고정 action 트리의 click handler에 버블링하지 않는다. UC4 테마,
|
||||
UC6 전문가와 UC7 거래정지는 원본처럼 **단일 클릭**으로 선택/playlist 동작을 수행하고,
|
||||
@@ -74,10 +84,10 @@ fixed/industry/comparison 트리의 원본 double-click과 독립적으로 처
|
||||
|---|---|---|
|
||||
| `Form1_Load` | 자산·DB·탭·Tornado 초기화 | WebView local UI와 C# composition root 초기화; 기본 `DryRun` |
|
||||
| `tabControl1_SelectedIndexChanged` | 탭별 최초 데이터 조회 | 10개 identity별 C# activation gate; 최초 진입 1회 load, 재진입 snapshot 유지 |
|
||||
| 탭 drag 이벤트 | 10개 탭 표시 순서 교환 | identity 기반 drag/키보드 이동; active tab·playlist 불변 |
|
||||
| 탭 drag 이벤트 | 10개 탭 표시 순서 교환 | dragover 대상 진입 시 identity와 예상 위치를 C#이 검증해 교환; 중복 전달은 no-op, active tab·playlist 불변 |
|
||||
| 검색 버튼/Enter | 종목 검색 | 원본 KOSPI→KOSDAQ→NXT 순서와 마지막 이름 일치 규칙 유지 |
|
||||
| 컷 click/double-click/drag | 원본 31컷 선택·추가 | plain/Ctrl/Shift/Ctrl+Shift와 원본 double-click 판정, batch 추가 |
|
||||
| playlist click/key/buttons | 선택, enabled, 이동, 삭제 | C# playlist authority; PREPARED/PROGRAM/pending/unknown에서 mutation 차단 |
|
||||
| playlist click/key/buttons/drag | 선택, enabled, 이동, 삭제, 다중 선택 행 이동 | 선택된 행은 원래 순서를 보존한 한 블록으로 임의 위치에 이동; C# playlist authority와 PREPARED/PROGRAM/pending/unknown mutation 차단 유지 |
|
||||
| F2/F3 | 배경 선택·없음 | trusted sibling background root만 허용; 누락·reparse·escape fail closed |
|
||||
| F8 | TAKE IN | idle이면 내부 PREPARE → TAKE IN을 한 번에 실행 |
|
||||
| NEXT | Page NEXT 또는 다음 행 | 같은 scene PageN 여부를 C#이 판정 |
|
||||
@@ -91,6 +101,8 @@ FarPoint UI는 Web table/list로 표현한다. 다음 의미는 원본과 같이
|
||||
- plain/Ctrl/Shift/Ctrl+Shift 선택과 현재 행
|
||||
- column header 정렬과 현재 표시 순서
|
||||
- 위/아래 이동, 선택/전체 삭제와 enabled 토글
|
||||
- playlist의 비연속 다중 선택을 한 블록으로 유지하는 행 drag와 임의 before/after drop
|
||||
- UC6/EList 추천 행의 opaque `rowId` 기반 drag 재정렬
|
||||
- single-click과 double-click을 컨트롤별로 구분
|
||||
- 부모 section 전체 추가는 모든 자식을 먼저 materialize한 뒤 한 번에 commit
|
||||
- 수동/지원 불가 child가 있으면 부분 추가 없이 전체 차단
|
||||
@@ -101,6 +113,34 @@ GraphE 행 double-click은 fresh DB record를 다시 확인한 뒤 한 행을
|
||||
Theme 결과 double-click은 원본의 5행 현재가 경로를 사용한다. PList 행 double-click은
|
||||
현재 save/load 모드에 맞춰 동작하며, 이름만으로 DB identity를 추정하지 않는다.
|
||||
|
||||
### drag 이관 경계
|
||||
|
||||
| 원본 동작 | Web 입력 | C# 권위와 중복 안전 |
|
||||
|---|---|---|
|
||||
| `PlayList_DragDrop/DragOver` | 내부 custom MIME와 opaque source/target `rowId`, before/after | source가 선택 행이면 현재 선택 전체를 표시 순서대로 이동한다. 체크박스에서 시작한 drag는 거부하고 PREPARED/PROGRAM/pending/unknown에서는 변경하지 않는다. |
|
||||
| `tab_DragOver/MouseDown/Move/Up` | drop을 기다리지 않고 dragover로 `hover-swap-tabs` 전송 | C# 탭 identity와 `expectedSourceIndex/expectedTargetIndex`가 현재 순서와 일치할 때만 교환하므로 같은 메시지의 중복 전달이 순서를 되돌리지 않는다. |
|
||||
| UC6 `FpSpread2.AllowDragDrop` | ThemeA/EList 편집행의 내부 custom MIME와 opaque `rowId` | 워크플로가 임의 before/after 위치를 계산한다. 존재하지 않는 ID, 같은 행, 추가 payload 필드는 strict bridge에서 거부하거나 no-op 처리한다. |
|
||||
|
||||
실제 마우스 검증에서는 playlist 행 drop이 조상 drop zone으로 버블링해 현재 선택된 컷을
|
||||
한 번 더 추가하는 문제가 드러났다. 조상은 이제 exact `legacy-selected-cuts` `text/plain`
|
||||
token만 처리하고 playlist row custom MIME와 외부 text는 무시한다. 따라서 한 row drop에서
|
||||
reorder와 cut append가 함께 발생하지 않는다.
|
||||
|
||||
체크박스 origin도 브라우저 동작을 반영해 보강했다. Chromium의 `dragstart.target`은 실제
|
||||
pointer가 체크박스에서 시작했어도 draggable 조상 행일 수 있다. pointerdown 때 checkbox
|
||||
origin row를 기억해 이어지는 dragstart를 거부하고 pointerup/pointercancel/dragend에서 지운다.
|
||||
회귀 테스트는 이 target 형태, 다중선택 보존, row MIME의 조상 무시, 외부 text 거부와 exact
|
||||
selected-cut token의 1회 처리를 DOM event 순서로 재현한다.
|
||||
|
||||
### ThemeA 이름 중복확인
|
||||
|
||||
원본 ThemeA의 `중복확인` 버튼을 `operator-catalog-name-check`로 이관했다. Web은 이름만
|
||||
`check-operator-catalog-theme-name` intent로 전송하고 KRX/NXT, 코드와 테이블 identity는
|
||||
C# workflow가 소유한다. 선택된 provider의 `SB_LIST`에 exact title parameterized
|
||||
`COUNT(*)` 조회를 한 번 수행하며 DB mutation은 실행하지 않는다. 중복, 사용 가능,
|
||||
결과 불명 상태를 구분하고, 조회 결과를 확정할 수 없으면 쓰기 없이 fail closed한다.
|
||||
원본처럼 편집 중 자기 행을 제외하지 않으므로 이름을 바꾸지 않은 행은 중복으로 판정된다.
|
||||
|
||||
## 원클릭 TAKE IN과 숨김 PREPARE
|
||||
|
||||
원본 운영 화면의 핵심 동작은 별도 PREPARE를 먼저 누르는 것이 아니라 F8/TAKE IN 한 번으로
|
||||
@@ -115,6 +155,46 @@ Theme 결과 double-click은 원본의 5행 현재가 경로를 사용한다. PL
|
||||
`hidden`이다. TAKE IN 실패·timeout·`OutcomeUnknown`이면 자동 재시도하지 않으며 성공한
|
||||
prepared ownership을 추측해 지우지 않는다.
|
||||
|
||||
## Visual Studio Development Live 시작 경계
|
||||
|
||||
공유 `MBN_STOCK_WEBVIEW.slnLaunch`와 패키지 시작 프로필은
|
||||
`MBN_STOCK_WEBVIEW.LegacyParityApp`을 명시적인 시작 프로젝트로 사용한다. 저장소의
|
||||
기본값은 계속 `DryRun`이고 이 Development Live 부트스트랩은 Release에서 적용되지 않는다.
|
||||
Development Live는 정확한 `--development-live`
|
||||
인자, Debug 빌드, `%LOCALAPPDATA%` 아래 Git 제외 승인 파일의 세 조건을 모두 만족한
|
||||
프로세스에서만 구성된다.
|
||||
|
||||
승인 파일은 정확한 다섯 속성, 최대 4096바이트, canonical JSON, exact authorization
|
||||
문자열과 독립 검수된 native/Interop SHA-256 두 개를 요구한다. 알 수 없는 속성, 중복 속성,
|
||||
reparse 경로, I/O 오류 또는 일부 환경 설정 실패는 모두 fail closed한다. Live authorization은
|
||||
process scope에서 마지막에 설정되고 `MainWindow`/engine 생성 시 한 번 캡처된다. 이 경로는
|
||||
기존 `trustedLiveOutputEnabled`, scene allowlist, asset 검사와 명령 안전 게이트를 완화하지
|
||||
않는다. 상세 절차는
|
||||
[`DEVELOPMENT_LIVE_VISUAL_STUDIO.md`](DEVELOPMENT_LIVE_VISUAL_STUDIO.md)에 있다.
|
||||
|
||||
## 2026-07-15 실제 UI·package·연결 검증
|
||||
|
||||
설치한 signed Release x64 MSIX는 **15,213,188 bytes**, SHA-256
|
||||
`357E17426C45FF516592EE0177D0F95502A98AF084759348ABC191BA5ED21FD5`다. 설치와
|
||||
package-context 실행을 확인했다. Release에 `--development-live`를 전달한 회차는 Debug-only
|
||||
gate 때문에 `DryRun`으로 남았고 Tornado TCP 연결과 Network Monitoring 변경이 없었다.
|
||||
|
||||
실제 WebView 마우스/CDP 입력의 확인 범위는 다음과 같다.
|
||||
|
||||
- `삼성` 검색 결과 **63개**, `삼성출판사` 선택, 선택한 컷 3개를 한 번의 drop으로
|
||||
playlist 3행에 추가
|
||||
- playlist multi-row block reorder와 enabled 체크박스 origin drag 차단
|
||||
- mouse release 전에 dragover로 시장 탭 순서 교환
|
||||
- EList 추천행 **5개** drag reorder. 수량 입력칸에서 시작한 실제 마우스 drag는 순서를
|
||||
바꾸지 않고, 행의 비입력 영역에서 시작한 drag만 순서를 바꾸는 것을 확인
|
||||
- ThemeA 결과 **500건**과 exact-title `중복확인` read 성공
|
||||
|
||||
별도 승인된 Development Live 회차의 장비 로컬 시간(KST) **14:28:28**에 HELLO request와
|
||||
success를 각 1회, **14:43:10**에 BYE 1회를 확인했다. scene, PREPARE, TAKE 계열, DB write는
|
||||
모두 0건이다. 최종 Network Monitoring 원문은 **300,007자**, SHA-256
|
||||
`45858322F60C135858002EB6243D0474F51F1965E23D2332D397C3A3B5DB8049`다. 이 회차는
|
||||
Live 연결/해제 경로만 검증하며 scene/PGM 방송 송출 성공을 뜻하지 않는다.
|
||||
|
||||
## PageN과 NEXT
|
||||
|
||||
| scene | page size | 규칙 |
|
||||
@@ -167,9 +247,12 @@ create/save → fresh readback → delete → absence를 통과했다.
|
||||
| GraphE | [LegacyManualFinancialWorkflow.cs](../src/MBN_STOCK_WEBVIEW.LegacyApplication/ManualFinancial/LegacyManualFinancialWorkflow.cs) | [manual-financial tests](../tests/MBN_STOCK_WEBVIEW.LegacyApplication.Tests/ManualFinancial) |
|
||||
| PList/AList | [LegacyNamedPlaylistWorkflow.cs](../src/MBN_STOCK_WEBVIEW.LegacyApplication/NamedPlaylist/LegacyNamedPlaylistWorkflow.cs) | [named-playlist tests](../tests/MBN_STOCK_WEBVIEW.LegacyApplication.Tests/NamedPlaylist) |
|
||||
| ThemeA/EList | [LegacyOperatorCatalogWorkflow.cs](../src/MBN_STOCK_WEBVIEW.LegacyApplication/OperatorCatalog/LegacyOperatorCatalogWorkflow.cs) | [catalog tests](../tests/MBN_STOCK_WEBVIEW.LegacyApplication.Tests/OperatorCatalog) |
|
||||
| Designer 이벤트 감사 | [LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md](LEGACY_DESIGNER_EVENT_PARITY_AUDIT.md) | 186 subscriptions / 171 unique handlers |
|
||||
| VS Development Live | [DEVELOPMENT_LIVE_VISUAL_STUDIO.md](DEVELOPMENT_LIVE_VISUAL_STUDIO.md) | strict local authorization와 Debug-only bootstrap |
|
||||
| scene matrix | [SCENE_EQUIVALENCE.md](SCENE_EQUIVALENCE.md) | 35/35 builder, 45 alias, PageN matrix |
|
||||
| 2026-07-15 증적 | [LEGACY_PARITY_VALIDATION_20260715.md](LEGACY_PARITY_VALIDATION_20260715.md) | 최종 전체 회귀 기록란 포함 |
|
||||
| 2026-07-15 증적 | [LEGACY_PARITY_VALIDATION_20260715.md](LEGACY_PARITY_VALIDATION_20260715.md) | signed Release, 실제 UI와 제한된 Live 연결 범위 |
|
||||
|
||||
최종 Debug/Release 전체 테스트 개수, 새 MSIX SHA-256와 개발 PGM 결과는 병렬 변경을
|
||||
모두 합친 뒤 위 검증 문서에 기록했다. 이전 package 숫자나 hash를 현재 결과로
|
||||
재사용하지 않았다.
|
||||
현재 signed Release MSIX의 hash·크기·설치·DryRun 실행과 위 실제 마우스/CDP UI 범위는
|
||||
확인했다. 최종 회귀는 .NET Debug/Release x64에서 각각 **2,446/2,446**, Web Node에서
|
||||
**438/438**, Visual Studio 2026 Debug/Release x64 빌드에서 경고 0·오류 0이다. 다만
|
||||
HELLO/BYE만 수행한 Live 회차를 scene PREPARE/TAKE/PGM 성공으로 확대하지 않는다.
|
||||
|
||||
Reference in New Issue
Block a user