140 lines
29 KiB
Markdown
140 lines
29 KiB
Markdown
# 원본 기능 재감사 기준표
|
||
|
||
감사 기준일: 2026-07-12
|
||
원본(읽기 전용): `C:\Users\MD\source\repos\MBN_STOCK_N`
|
||
마이그레이션 대상: `C:\Users\MD\source\repos\MBN_STOCK_WEBVIEW`
|
||
|
||
이 문서는 원본 WinForms/FarPoint 프로그램과 현재 WinUI 3/WebView2 프로그램을 다시 대조한 결과다. 원본 저장소와 실제 Cuts는 읽기 전용으로 조사했다. 자동 테스트나 UI 코드가 존재한다는 사실과 실제 운영 환경에서 동등성이 확인됐다는 사실을 구분한다.
|
||
|
||
## 상태 정의
|
||
|
||
| 상태 | 의미 |
|
||
|---|---|
|
||
| `미적용` | 원본 동작의 대응 구현 또는 필수 검증 경로가 아직 없다. |
|
||
| `적용 중` | 현재 작업 트리에 구현 또는 검사 보강이 있으나 최종 패키지·실환경 검증까지 끝나지 않았다. |
|
||
| `완료` | 현재 코드와 해당 자동 검증에 반영됐고 이번 재감사에서 완료로 판정했다. |
|
||
| `외부자산 필요` | 코드만으로 완료할 수 없으며 Git/MSIX 밖의 승인된 자산이나 운영 환경이 필요하다. |
|
||
|
||
완료 수는 증분 포팅과 최종 회귀 결과에 따라 바뀌므로 아래 표를 단일 기준으로 사용한다. 기존 문서에서 사용하는 `완료`, `통합 완료`, `전체 통과` 표현도 아래 상태와 검증 범위로 다시 해석해야 한다.
|
||
|
||
## 우선순위별 결과
|
||
|
||
| ID | 우선순위 | 기능·누락 후보 | 상태 | 근거 파일·메서드 | 현재 판정 | 검증 방법 |
|
||
|---|---|---|---|---|---|---|
|
||
| LF-001 | P0 | `s6001` 해외지수 영상 자산 | 외부자산 필요 | 현재 `src/MBN_STOCK_WEBVIEW.Core/Playout/Scenes/ReadOnlyPanelSceneBuilders.cs:491-513`, `S6001SceneMutationBuilder.Metadata`/`Index`; 검증기 `src/MBN_STOCK_WEBVIEW.Playout/Configuration/ValidatedPlayoutOptions.cs:375-406`, `ResolveAssetPath` | 해외지수 15개 target이 13개 `Video\20201008_<국가>.vrv`에 의존한다. 감사 시 승인 Cuts의 `Video` 폴더는 비어 있어 이 target들은 DryRun PREPARE에서도 COM 호출 전에 차단된다. 유가·금의 PNG/JPG는 존재한다. | 승인된 파일을 Cuts root 아래에 제공한 뒤 강화된 cut/asset 검사와 s6001 각 target DryRun PREPARE를 실행한다. 실제 PGM은 별도 승인 회차에서만 확인한다. |
|
||
| LF-002 | P0 | cut coverage의 장면 종속 asset 검사 | 완료 | `scripts/LegacyCutRequirements.json`, `LegacyCutCoverage.psm1`, `Test-LegacyCutCoverage.ps1`; 테스트 `tests/Scripts/Test-LegacyCutCoverage.Tests.ps1`, `LegacyCutRequirementManifestTests.cs` | 45개 active alias와 23개 장면 종속 asset을 분리해 존재·0바이트·root escape·reparse·manifest 중복을 검사한다. 완전/누락/0바이트/reparse/escape fixture가 자동 테스트에 연결됐다. 실제 승인 Cuts read-only 실행은 alias missing/unsafe 0, asset unsafe 0, asset missing 14로 정확히 실패했다: `s5006` 1개와 `s6001` 13개 영상이다. | 실제 누락 14개가 승인 Cuts에 제공되면 같은 명령을 다시 실행해 `Status=Passed`를 확인한다. 검사기 완료와 외부 자산 준비 완료는 LF-001/LF-003에서 분리한다. |
|
||
| LF-003 | P0 | `s5006` 큐브 배경 영상 | 외부자산 필요 | 원본 `MBN_STOCK_N/Scene/s5006.cs:30-31`; 현재 `src/MBN_STOCK_WEBVIEW.Core/Playout/Scenes/ReadOnlyPanelSceneBuilders.cs:31-48`; `docs/PLAYOUT_OPERATIONS.md:81-85` | `Video\큐브배경.vrv`가 승인 Cuts에 없다. 기존 운영 문서에는 누락이 기록돼 있으나 파일 제공 전에는 `s5006` PREPARE가 완료된 것이 아니다. | asset 검사 통과 후 s5006 DryRun PREPARE, 승인된 Test/PGM 회차 순으로 검증한다. |
|
||
| LF-004 | P0 | 실제 운영 DB write | 미적용 | `docs/OPERATOR_UI_PARITY.md:48-62,167-170,214-218,229-246,278`; GraphE `MainWindow.ManualFinancial.cs`; PList `MainWindow.NamedPlaylists.cs`; ThemeA/EList `MainWindow.OperatorCatalogs.cs` | mutation 계약, fake executor, rollback·OutcomeUnknown 테스트는 존재하지만 GraphE, PList/AList, ThemeA, EList의 운영 Oracle write는 실행하지 않았다. FSell/VI도 격리 저장소 write만 검증했다. 따라서 운영 데이터 쓰기 동등성은 미검증이다. | 승인된 테스트용 식별자와 사전 snapshot을 정하고 create/update/delete를 각 1회 실행한다. 매 단계 후 별도 read-only 조회로 결과를 대조하고, timeout·OutcomeUnknown이면 반복하지 않는다. 운영 데이터에는 임의로 실행하지 않는다. |
|
||
| LF-005 | P0 | 전체 장면·운영 UI의 실제 Tornado2/PGM 검증 | 미적용 | `docs/MIGRATION.md:69-74`; `docs/OPERATOR_UI_PARITY.md:48-62`; `docs/PLAYOUT.md:348-366` | 승인된 실제 회차의 범위는 5001/5074와 그 Page/playlist NEXT, refresh, TAKE OUT이다. 자동 builder/DB smoke 결과를 나머지 장면의 PGM 동등성으로 확대할 수 없다. | 장면별 허용 자산과 DB 전제조건을 먼저 통과시킨다. 이후 회차별 계획 SHA-256과 명시적 승인을 받아 Network Monitoring 명령, callback, PGM 화면을 함께 기록한다. |
|
||
| LF-006 | P1 | 시스템 종료 확인 | 완료 | `MainWindow.CloseConfirmation.cs`, `EnsureCloseConfirmationAttached`, `OnAppWindowClosing`, `BuildCloseConfirmationMessage`, `DetachCloseConfirmation`; 연결부 `MainWindow.xaml.cs:54-63,101-112,OnClosed`; 테스트 `tests/Web/operator-ui-app-integration.test.cjs:384-408` | 모든 시스템 close를 먼저 취소하고 기본 버튼이 취소인 확인창을 연다. PREPARED/PROGRAM, command pending, OutcomeUnknown에 맞는 경고를 표시하며 종료 과정에서 TAKE OUT이나 반대 명령을 자동 실행하지 않는다. | Web 통합 테스트를 실행하고 패키지 앱에서 idle, prepared/on-air 경고, 취소, 명시적 종료를 수동 확인한다. |
|
||
| LF-007 | P1 | 패키지 앱 단일 인스턴스 | 완료 | `App.xaml.cs:9-57`, `OnLaunched`, `OnMainInstanceActivated`; 테스트 `tests/Web/operator-ui-app-integration.test.cjs:72-88` | `AppInstance.FindOrRegisterForKey`가 MainWindow와 DB/WebView/playout runtime 생성 전에 실행된다. 두 번째 인스턴스는 activation을 primary로 전달한 뒤 종료하며 기존 프로세스를 이름으로 찾아 강제 종료하지 않는다. | 통합 테스트 후 설치된 MSIX를 두 번 실행해 프로세스 하나, 창 하나, 기존 창 활성화를 확인한다. |
|
||
| LF-008 | P1 | 운영자 모달의 전역 단축키 격리 | 완료 | `Web/app.js:6808-6845`, `hasOpenOperatorModal`, `isolateOperatorModalShortcut`; 테스트 `tests/Web/operator-ui-app-integration.test.cjs:410-429` | GraphE, FSell/VI, ThemeA/EList 등 modal이 열려 있으면 F2/F3/F8/Escape, Home/End/Delete/Space, Ctrl+K가 workspace 송출·playlist handler로 전달되지 않는다. F8/Escape에는 modal을 먼저 닫으라는 안내를 표시한다. | Web 통합 테스트 후 각 modal 입력 필드에서 해당 키를 눌러 playout command와 playlist mutation이 발생하지 않는지 확인한다. |
|
||
| LF-009 | P1 | PList의 기존 한국어 `DC_TITLE`/`LIST_TEXT` 복원 | 적용 중 | 원본 `MBN_STOCK_N/Form/PList.cs:81-124`, `data_load`; 현재 `src/MBN_STOCK_WEBVIEW.Core/Data/NamedPlaylistPersistence.cs:442-540,742-787`, `LoadAsync`/`ParseItem`; `Web/named-playlist-workflow.js:334-412`, `restoreRawRows`; `Web/app.js:4317-4619,5017-5052` | 운영 Oracle read-only 집계에서 활성 정의 23개와 연결된 2,213행은 모두 정확히 7필드였고 canonical ASCII group은 0행, malformed/null은 0행이었다. 즉 전 행이 기존 한국어 형식이므로 legacy→canonical 복원이 필수다. 삭제된 정의에 연결된 orphan 88개 프로그램/9,369행은 현재 UI load 대상이 아니다. 닫힌 매퍼와 fresh identity 재검증을 보강 중이며 전체 2,213행의 unique/blocked 판정이 끝나기 전에는 완료로 보지 않는다. | 실제 read-only PList 행을 원본과 새 앱에서 같은 프로그램 코드로 읽어 `DC_TITLE`과 caret 7개 필드를 글자 단위로 비교한다. `<60>` 또는 mojibake가 없어야 하며 trusted restore와 fresh page plan 전에는 PREPARE가 계속 차단돼야 한다. raw 값은 로그·문서에 출력하지 않고 분류 건수만 기록한다. |
|
||
| LF-010 | P1 | 원본 F2/F3 배경 디렉터리 동등성 | 코드 적용 / 외부자산·패키지 검증 대기 | 원본 `MBN_STOCK_N/MainForm.cs:4008-4054`, `btnback_Click`, `ckback_CheckedChanged`; 현재 `MainWindow.Background.cs`, `PlayoutSceneCompositionFactory`, `TrustedPlayoutAssetPath`, `ValidatedPlayoutOptions`; 문서 `docs/TRUSTED_BACKGROUND_ROOT.md` | Cuts gate를 유지한 채 별도 `LegacyBackgroundDirectory`를 추가했고, 생략 시 원본처럼 `SceneDirectory\..\배경`을 계산한다. F2는 유효할 때만 picker 전 `기본.vrv`를 복원하고 F3-on은 항상 기본 파일을 다시 검증한다. root escape·조상/파일 reparse·hardlink·누락·opened-handle final path를 fail closed로 검사하며 Cuts fallback은 없다. 이 장비의 원본 `bin\Debug\배경`과 `기본.vrv`는 실제로 없어 현재 기본 배경은 잠긴다. | Core Debug/Release 1,259/1,259, Playout Debug/Release 387/387과 앱 Debug/Release x64 build를 통과했다. signed 패키지에서 별도 root 상태 메시지와 F2/F3를 확인하고, 자산 제공 뒤 다음 PREPARE mutation/PGM은 승인 회차에서 검증한다. |
|
||
| LF-011 | P1 | `종목비교.dat` 기존 저장쌍 이전 | 적용 중 | 원본 `MBN_STOCK_N/Control/UC3.cs:34-55,181-185`, `UC3_Load`, `Data_Load`, `File_Save`; 현재 `src/MBN_STOCK_WEBVIEW.Core/Data/LegacyComparisonPairImport.cs`, `MainWindow.LegacyComparisonImport.cs`, `Web/comparison-import-workflow.js`, `Web/app.js`; 테스트 `LegacyComparisonPairImportServiceTests.cs`, `comparison-import-workflow.test.cjs`, `comparison-import-app-integration.test.cjs` | 원본 파일은 CP949 358바이트, 비어 있지 않은 8행, 각 행 정확히 9필드이며 0~3열만 값이 있다는 감사 fixture를 SHA-256 `1EE76BC4…BFC0D2F2`로 고정했다. Web이 경로를 전달하지 않는 고정 read-only source, reparse/크기/2회 quiescent snapshot 검사, strict CP949/9필드 parser, 현재 Oracle/MariaDB 종목·해외 identity exact read, 고정 시장명과 해외 동명이름 충돌 차단, 전체 중복·500쌍 경계, 명시적 버튼과 one-time marker/rollback을 구현했다. 원본은 수정하지 않고 성공 뒤 WebView private `localStorage` schema만 사용한다. 이 장비의 실제 설정으로 동일 서비스 read-only smoke를 실행해 8행 전부와 SHA-256이 일치하고 모든 identity가 해소됨을 확인했다. 다만 패키지 UI 버튼→localStorage→재시작 marker까지의 1회 실행은 아직 하지 않았으므로 완료로 올리지 않는다. | 실제 패키지에서 명시적 버튼 1회로 8행을 모두 fresh DB 재검증하고 local schema/hash/순서를 확인한다. 같은 profile의 두 번째 실행은 marker로 차단되고, 원본 변경·손상·동명이름·기존쌍 중복은 부분 저장 없이 전체 fail closed여야 한다. |
|
||
| LF-012 | P1 | FSell/VI 원본 `Data`의 안전한 이전과 설정 문서 | 적용 중 | 원본 `MBN_STOCK_N/MainForm.cs:338-339`, `FSell.cs:31-88`, `VIList.cs:31-34,137-139`; 현재 `src/MBN_STOCK_WEBVIEW.Core/Data/LegacyManualOperatorDataImport.cs`, `src/MBN_STOCK_WEBVIEW.Infrastructure/Playout/LegacyManualOperatorDataImporter.cs`, `MainWindow.ManualLists.cs`, `Web/manual-lists-workflow.js`, `Web/manual-lists-ui.js` | UserProfile 아래 고정 원본 경로만 read-only로 두 번 읽고 strict CP949, FSell 파일별 5행+종료 레코드, VI 9열·최대 100건·4,000바이트를 검사한다. 명시적 확인 뒤 private store가 완전히 비어 있을 때만 4개 staged 파일을 no-overwrite로 옮기고 production parser readback 후 v1 marker를 마지막에 기록한다. rollback을 확정하지 못하면 OutcomeUnknown quarantine이며 자동 재시도하지 않는다. 실제 source smoke는 FSell 15행·VI 9건·aggregate SHA-256 `fd39a363…a2114`였고, 이 장비의 private 4개 파일은 이미 원본과 각각 byte-identical이어서 `DestinationNotEmpty`로 source read 전 중단했으며 전후 SHA가 같았다. | 새 빈 package profile fixture에서 버튼→4파일→marker→재시작 차단을 확인한다. 현재 운영 profile에서는 기존 동일 파일을 덮어쓰거나 marker를 임의 생성하지 않는다. |
|
||
| LF-013 | P1 | generic native `bridge-error` 표시 | 적용 중 | producer `MainWindow.xaml.cs:431-437`, `MainWindow.Playout.cs:121-126,370-375`; 현재 consumer `Web/app.js:6446-6454`, `handleBridgeError`, `handleNativeMessage`; 테스트 `tests/Web/operator-ui-app-integration.test.cjs:431-435` | 재감사 당시 소비자가 없던 오류 표시가 현재 작업 트리에 반영됐다. bounded 메시지와 운영 로그 표시는 확인되지만 최종 회귀·패키지 반영 전이라 완료로 올리지 않는다. | malformed status/quarantine payload fixture로 `bridge-error` 1회, bounded toast/log, playout state 불변을 확인하고 전체 Web 테스트와 패키지 UI를 다시 검증한다. |
|
||
| LF-014 | P2 | 영구 운영 로그 | 적용 중 | 원본 `MBN_STOCK_N/MainForm.cs:84-128,132-180,542-543,675,776`, `initAliveChecker`, `LogWrite`, `timerAliveChecker_Tick`; 현재 `src/MBN_STOCK_WEBVIEW.Infrastructure/Diagnostics/NativeOperatorLogWriter.cs`, `NativeOperatorLogTransitions.cs`, `MainWindow.NativeOperatorLog.cs` | `%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Logs\Log_MMdd.log`에 Startup/Shutdown, Oracle/MariaDB·Tornado 전이, 실행 gate를 통과한 PREPARE/TAKE IN/NEXT/TAKE OUT의 요청과 terminal 결과만 기록한다. 4MiB/31일, provider별 중복 억제, single-command terminal, reparse/handle 검증을 적용했다. `TimedOut`과 불명확 결과는 `OutcomeUnknown` 한 번으로 끝내며 late result를 기록하지 않는다. 공개 record는 폐쇄 enum만 받아 requestId, 장면, 경로, SQL, DB message와 예외 문자열을 구조적으로 받을 수 없다. | Debug/Release 자동 검증 후 package context에서 시작→DB/DryRun 상태→종료를 실행하고 파일 재시작 잔존, 중복 억제, 금지 문자열 부재를 확인한다. |
|
||
| LF-015 | P2 | 호출자가 없는 native bridge handler | 완료 | `MainWindow.xaml.cs`, `OnWebMessageReceived`; 테스트 `tests/Web/operator-ui-app-integration.test.cjs` | Web 호출자가 없던 `open-external`과 `reload` message case를 native allowlist에서 제거했다. 외부 navigation/new-window 처리와 WebView process failure의 내부 reload 복구 메서드는 별도 native event 경로로 유지한다. | 정적 계약 테스트에서 두 message case와 Web 발신 literal이 모두 없음을 확인했다. |
|
||
| LF-016 | P2 | 실제 preview 이미지·영상 | 외부자산 필요 | `docs/MIGRATION.md:73-74`; 원본 `MBN_STOCK_N/MainForm.cs:1448-1462,1894-1911,2919-2921` | 현재 preview는 안전한 DTO/mutation 텍스트 중심이다. 실제 이미지·영상 연결은 후속 자산이다. 다만 원본 thumbnail 호출과 watcher는 주석 또는 미호출이므로 활성 원본 동등성의 P0/P1 blocker로 보지 않는다. | 승인된 preview 자산이 생기면 asset root와 노출 정보 검사를 거쳐 패키지 화면에서 확인한다. |
|
||
| LF-017 | P1 | 모든 업무 탭에서 계속 보이는 종목 검색·31컷 | 적용 중 | 원본 `MBN_STOCK_N/MainForm.Designer.cs:2022-2036,2454-2462`; 현재 `Web/index.html`의 독립 `stock-panel`, `Web/app.js`의 `renderStockWorkflow`; 테스트 `operator-ui-app-integration.test.cjs` | 종목 검색·31컷을 catalog panel 밖의 독립 열로 옮기고 모든 업무 메뉴에서 항상 표시한다. 1920 브라우저에서 11개 메뉴를 이동해 검색어, 표시, 31개 행이 유지되고 문서 가로 overflow가 없음을 확인했다. | signed MSIX에서 실제 DB 검색 결과·선택 종목이 모든 탭 전환 뒤 유지되고 컷 추가가 같은 identity를 쓰는지 확인한 뒤 완료로 올린다. |
|
||
| LF-018 | P2 | 원본 트리·컷 목록 일괄 추가 제스처 | 적용 중 | 원본 부모 double-click `MBN_STOCK_N/Control/UC1.cs:141-180`; 소스 컷 Ctrl/Shift 선택 `MBN_STOCK_N/MainForm.cs:3427-3525,3534-3549,3635-3643`; 현재 `Web/legacy-batch-selection-workflow.js`, `Web/app.js`; 테스트 `legacy-batch-selection-*.test.cjs` | 종목 31컷의 plain/Ctrl/Shift/Ctrl+Shift 선택, 단일 double-click, `선택 컷 추가`를 포팅했다. 해외·환율·지수 fixed source의 섹션 `전체 추가`는 모든 자식을 먼저 materialize한 뒤 원본 순서로 한 번에 commit하며, 수동/지원불가가 한 건이라도 있으면 부분 추가 없이 전체 차단한다. 실제 브라우저에서 5개 선택, 해외 43개 순서 추가, 수동 혼합 섹션 0건 추가를 확인했다. | signed MSIX 확인 뒤 업종·비교·테마 등 전용 source group의 부모 전체 추가가 원본에서 실제로 필요한 범위를 계속 분리 포팅한다. source drag/drop 자체는 오조작 검증 뒤 결정한다. |
|
||
| LF-019 | P1 | 저장 PList의 `테마_NXT` stale code 복원 | 적용 중 | 원본 `Control/UC4.cs`, `Scene/s5074.cs`, `s5077.cs`, `s5088.cs`; 현재 `LegacyNamedNxtThemeRestoreService`, `MainWindow.NamedNxtThemeRestore.cs`, `Web/named-nxt-theme-restore-workflow.js`; 상세 `docs/NAMED_NXT_THEME_RESTORE.md` | 원본처럼 제목 exact lookup으로 현재 Maria code를 찾고 현재가 전용 5/6/12행, 정렬 fallback, 00~12 PRE/13~23 AFTER, fresh PageN을 닫힌 batch로 복원한다. 실제 활성 48행/24제목은 모두 current identity가 유일하고 저장 code 48개가 전부 stale였지만 현재 preview가 전부 비어 있어 48행 모두 `PreviewEmpty`로 정상 차단됐다. KRX 테마는 후보가 아니다. | Maria `SB_ITEM`/`v_all_stock` live 연계가 복구된 뒤 같은 read-only audit에서 한 행 이상 live item을 확인하고, fresh page preflight와 Debug/Release/MSIX UI를 검증한다. 실제 PGM은 별도 승인 회차가 필요하다. |
|
||
| LF-020 | P2 | 원본 초기 업무 화면 `해외` | 적용 중 | 원본 `MainForm.Designer.cs`, 첫 TabPage `해외`; 현재 `Web/index.html`, `Web/app.js` 초기 `activeMarket` | 원본은 첫 업무 탭인 해외로 시작하지만 재감사 당시 새 앱은 dashboard로 시작했다. dashboard는 새 진단 화면으로 유지하면서 초기 active identity, 제목과 최초 조회를 해외로 맞추는 중이다. | Web 초기화 테스트와 signed MSIX 첫 실행에서 해외만 active이고 최초 DB 요청이 중복되지 않는지 확인한다. |
|
||
| LF-021 | P2 | 업무 탭 드래그 순서 변경 | 코드 적용 / 패키지 검증 대기 | 원본 `MainForm.Designer.cs:1063-1066` TabControl drag events, `MainForm.cs:3183-3312` `tab_MouseDown`/`tab_MouseMove`/`tab_DragOver`/`swapTabPages`; 현재 `Web/market-nav-reorder.js`, `Web/app.js`의 `marketNavReorder` controller; 테스트 `market-nav-reorder*.test.cjs` | 새 dashboard는 첫 위치에 고정하고 원본 10개 업무 button만 `data-market` identity로 교환한다. active DOM node와 view/DB/playlist state는 건드리지 않으며 local/session storage에 저장하지 않는다. drag token은 닫힌 형식으로 검증하고, Alt+위/아래는 인접 교환과 첫·마지막 경계를 제공한다. 입력, modal, PREPARE 이후 잠금에서는 실행하지 않는다. | 전용 10/10과 전체 Web 353/353, cut fixture, Debug/Release x64 build가 통과했다. signed MSIX에서 pointer drag, 키보드 포커스, active click 유지와 재시작 시 기본 순서 복원을 확인한다. |
|
||
| LF-022 | P2 | GraphE 검색 Enter 다음 찾기 | 적용 중 | 원본 `GraphE.Designer.cs:229`, `GraphE.cs:605`, `downSearch_Click`; 현재 `Web/manual-financial-ui.js`; 테스트 `manual-financial-ui.test.cjs` | 목록 수락 전 Enter는 기존 DB 조회를 유지하고, 이후 Enter는 현재 선택 다음 행부터 대소문자 무시 Contains로 한 건을 찾아 load한다. 원본처럼 마지막에서 처음으로 순환하지 않으며 pending·잠금·숨김 modal은 무동작이다. | 네 GraphE 모드 관련 테스트 39/39 후 signed MSIX에서 한 건·마지막·검색어 변경을 확인한다. |
|
||
| LF-023 | P2 | 전문가 추천 편집기의 Delete 키 | 적용 중 | 원본 `UC6.Designer.cs:571`, `UC6.cs:230`; 현재 `Web/operator-catalog-ui.js`; 테스트 `operator-catalog-ui.test.cjs` | expert draft의 포커스/선택 행에서만 Delete를 기존 `removeDraftItem`으로 처리한다. ThemeA, modal 밖, input/textarea/contenteditable에는 영향이 없고 잠금·DB write 중에는 삭제하지 않고 event만 dialog 내부에서 격리한다. | Web 전체 회귀와 signed MSIX EList/전문가 편집 modal에서 확인한다. |
|
||
|
||
## 활성 PLAY_LIST 2,213행 재분류
|
||
|
||
운영 Oracle의 활성 프로그램 정의 23개와 연결된 2,213행을 원문을 출력하지 않는 read-only 집계로 다시 분류했다. 삭제된 정의에 매달린 orphan 데이터 88개 프로그램/9,369행은 현재 PList의 정상 load 대상이 아니므로 아래 수치에 포함하지 않았다.
|
||
|
||
| 복원 분류 | 건수 | 판정 |
|
||
|---|---:|---|
|
||
| 기존 닫힌 매퍼와 fresh 검증으로 복원 | 1,573 | stock/fixed/expert/GraphE 등 기존 계약과 현재 master를 모두 통과하는 행 |
|
||
| DB 없이 추가 복원 가능 | 57 | 업종 fixed 24, 고정 시장·지수 2열판 33 |
|
||
| 현재 DB exact lookup 뒤 추가 복원 가능 | 228 | NXT theme 48(복원 경로 적용, 현재 preview empty로 전부 차단), 비교 graph 41, 해외종목 78, 해외지수 candle 61 |
|
||
| 현재 identity를 안전하게 증명할 수 없음 | 325 | KRX theme 300, 원본이 시장을 저장하지 않은 종목 2열판 25. 이름이나 과거 코드를 추정하지 않고 재선택이 필요함 |
|
||
| whitelist 불일치로 자동 복원 금지 | 30 | `s5001` fixed-nearest 기존 집계가 재감사 후보 40건과 달라 명시적 CASE 확정 전까지 차단 |
|
||
| 합계 | 2,213 | raw 행은 closed mapping과 fresh identity가 모두 성공해야만 playable entry가 됨 |
|
||
|
||
테마 635행은 별도로 다음과 같이 판정했다. KRX exact 문법 375행 중 현재 제목이 유일한 287행만 즉시 신뢰할 수 있고 88행은 stale이다. 정렬 토큰이 없는 199행과 기타 문법 13행은 원본 `s5074/s5077/s5088`의 최종 분기와 같이 모두 `GAIN_ASC` 의미지만, 현재 `SB_LIST`에서 제목이 사라져 playable하지 않다. NXT 48행은 24개 저장 제목으로 구성되고 raw grammar는 `5단 표그래프 / 테마-현재가(입력순)` 한 종류다. 48행 모두 제목의 현재 Maria identity는 유일하고 저장 code가 현재 code와 다르지만, 현재 validated preview가 0건이어서 전부 `PreviewEmpty`로 차단한다. live item이 생긴 경우에만 현재 code를 송출 selection에 사용하며, 원본과 같이 PREPARE 직전 로컬 시각 00~12시는 PRE, 13~23시는 AFTER로 다시 결정한다.
|
||
|
||
비교 후보 99행은 고정 지수쌍 33, 시장쌍이 보존된 KRX graph 41, 시장이 사라진 `종목` 2열판 25로 확정했다. 앞의 74행만 closed target 또는 Oracle의 시장+이름 exact lookup으로 복원한다. 마지막 25행은 오늘의 master에서 이름이 우연히 유일해도 원본 행이 KOSPI/KOSDAQ/NXT/해외 구분을 보존하지 않았으므로 자동 복원하지 않는다. NXT graph는 원본 UC1 자체가 지원하지 않았고 현재 graph loader도 Oracle KRX pair만 허용하므로 계속 차단한다.
|
||
|
||
해외지수 candle 61행은 UC5 고정 이름 세 개(Dow 22, Nasdaq 21, S&P500 18)와 5/20/60/120일 기간만 사용하며 240일 활성 행은 없다. 이름과 기간은 닫힌 표이지만 원본 LIST_TEXT가 symbol/nation을 저장하지 않으므로 DB-free로 분류하지 않는다. Oracle master에서 `F_INPUT_NAME`, expected symbol, `F_NATC=US`, `F_FDTC=0`의 exact identity를 다시 확인한 뒤에만 `s8010/PRICE` 선택을 발급한다.
|
||
|
||
이 수치는 “문자열을 해석할 수 있음”과 “현재 데이터로 송출할 수 있음”을 분리한다. identity 미확정 325행과 whitelist 미확정 30행에는 `R...` 임시 code나 가장 가까운 장면을 넣지 않는다. 화면에는 실패 행을 유지하고 PREPARE를 차단하며, 운영자가 현재 항목으로 다시 선택해야 한다.
|
||
|
||
## s6001 asset 검사 보강 기준
|
||
|
||
`s6001` 해외지수 target은 다음 13개 파일을 요구한다.
|
||
|
||
- `Video\20201008_미국.vrv`
|
||
- `Video\20201008_독일.vrv`
|
||
- `Video\20201008_영국.vrv`
|
||
- `Video\20201008_프랑스.vrv`
|
||
- `Video\20201008_일본.vrv`
|
||
- `Video\20201008_중국.vrv`
|
||
- `Video\20201008_홍콩.vrv`
|
||
- `Video\20201008_대만.vrv`
|
||
- `Video\20201008_싱가포르.vrv`
|
||
- `Video\20201008_태국.vrv`
|
||
- `Video\20201008_필리핀.vrv`
|
||
- `Video\20201008_말레이시아.vrv`
|
||
- `Video\20201008_인도네시아.vrv`
|
||
|
||
검사 보강은 다음 조건을 만족해야 한다.
|
||
|
||
1. `.t2s` alias 결과와 asset 결과를 별도 필드로 보고한다.
|
||
2. 상대 경로만 허용하고 Cuts root 탈출을 거부한다.
|
||
3. 파일 존재, 0바이트 여부, reparse point를 검사한다.
|
||
4. 누락된 상대 경로와 영향을 받는 builder를 운영자가 알 수 있게 하되 secret이나 외부 절대 경로를 출력하지 않는다.
|
||
5. asset이 없는 현재 장비에서는 전체 migration 완료가 아니라 `외부자산 필요`로 끝나야 한다.
|
||
6. 완전 fixture, 단일 누락, 복수 누락, 0바이트, reparse fixture를 자동화한다.
|
||
|
||
권장 검증 명령 형태:
|
||
|
||
```powershell
|
||
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\Test-LegacyCutCoverage.ps1 `
|
||
-CutRoot "<승인된 읽기 전용 Cuts root>"
|
||
```
|
||
|
||
검사 보강 전의 `Missing=0`은 `.t2s` alias만 의미하며 asset-ready 증거로 사용하면 안 된다.
|
||
|
||
## 원본 I/O 조사에서 제외 판정한 항목
|
||
|
||
- 활성 Print/Excel/FarPoint export/import 호출은 발견되지 않았다.
|
||
- `MainForm.cs:1767-1772,1796-1805`의 CSV playlist save/load는 주석 처리돼 있다.
|
||
- `MainForm.GetThumnail`과 preview watcher/`SaveImageFile` 호출도 활성 경로가 아니다.
|
||
- `s8086`은 scene builder는 존재하지만 원본 MainForm active alias가 없어 의도적으로 unreachable이다. 이를 UI 누락으로 계산하지 않는다.
|
||
- FarPoint의 표·선택·정렬·이동 자체는 Web table/workflow로 변환할 수 있지만, 변환 UI가 존재한다는 사실만으로 DB write나 PGM 동등성이 완료되지는 않는다.
|
||
|
||
## 기존 완료 문서 교정 후속
|
||
|
||
다음 문서는 구현 존재, 자동 계약 테스트, 실데이터 read smoke, 외부 asset readiness, 실제 DB write, 실제 PGM 검증을 서로 다른 열로 분리해야 한다.
|
||
|
||
| 문서 | 교정할 표현 | 후속 교정 내용 |
|
||
|---|---|---|
|
||
| `docs/MIGRATION.md:69-74` | MainForm/UC1~UC7과 전용 화면을 포괄적으로 `완료`로 표현 | `화면·bridge 구현`과 `운영 동등성 검증`을 분리한다. PList 한국어 복원, s6001 asset, 원본 파일 one-time import, DB write, 장면별 PGM 상태를 이 문서와 맞춘다. |
|
||
| `docs/OPERATOR_UI_PARITY.md:48-62` | 다수 화면을 `화면 통합 완료`로 표현 | 해당 표현은 구조적 UI 도달성만 뜻한다고 명시하고 DB-W/PGM 미검증을 상단 요약과 각 행에 유지한다. 완료 판정은 실제 검증 열까지 충족할 때만 사용한다. |
|
||
| `docs/OPERATOR_UI_PARITY.md:75,111-113,214-218` | PList와 비교쌍 load/save를 완료로 표현 | PList 한국어 실DB 복원과 `종목비교.dat` one-time import를 별도 미완료 항목으로 추가한다. |
|
||
| `docs/OPERATOR_UI_PARITY.md:77` | F2/F3 배경을 완료로 표현 | 별도 sibling `배경` root와 `기본.vrv` 코드/자동 검증은 반영됐다. 실제 자산이 없으므로 package/PGM 완료로 확대하지 않는다. |
|
||
| `docs/SCENE_EQUIVALENCE.md:17,98` | 전체 real-data smoke 및 s6001을 asset 경고 없이 통과로 표현 | DB→DTO→mutation smoke와 실제 asset preflight를 분리하고 s6001 국가 영상 13개를 `외부자산 필요`로 기록한다. |
|
||
| `docs/PLAYOUT_OPERATIONS.md:86,94` | s5025 환경 변수 안내와 alias-only cut 검사 | 정상 앱의 private manual store 경로와 one-time import 정책을 정확히 설명한다. cut coverage 결과에 asset 검사 상태를 추가한다. |
|
||
| `docs/PLAYOUT.md:97,348-366` | Web 배경 변경 불가 설명 및 자동 검증을 35개 완료 근거로 사용 | F2/F3 native picker의 실제 경계를 반영한다. 5001/5074 PGM 성공과 나머지 scene 자동 검증을 명확히 분리한다. |
|
||
|
||
이 교정은 기존 구현 성과를 취소하는 것이 아니라, `구현됨`과 `실제 방송 동등성 완료`를 같은 의미로 사용하지 않기 위한 것이다.
|
||
|
||
## 완료 판정에 필요한 최종 증거
|
||
|
||
1. s5006/s6001 포함 모든 reachable scene의 asset preflight 결과
|
||
2. PList 한국어 `DC_TITLE`/`LIST_TEXT` 실DB read 비교
|
||
3. 기존 `종목비교.dat`, FSell, VI 데이터의 안전한 one-time migration 결과
|
||
4. 승인된 테스트 데이터로 수행한 GraphE/PList/ThemeA/EList 및 manual file write read-back
|
||
5. Debug/Release x64 회귀와 Release MSIX package-context 실행
|
||
6. 승인된 scene·회차의 Network Monitoring 명령, callback, PGM 화면
|
||
7. timeout·OutcomeUnknown에서 재시도하지 않았다는 운영 기록
|
||
|
||
이 증거가 갖춰지기 전에는 전체 원본 UI 또는 35개 scene의 동등성 목표를 완료 처리하지 않는다.
|