# MBN_STOCK_WEBVIEW 이관 현재 기준선

기준 시각: 2026-07-22

기준 소스: `main` 브랜치의 이 문서 포함 최신 기준선

원본: `C:\Users\MD\source\repos\MBN_STOCK_N` (계속 읽기 전용)

이 문서는 현재 이관 완료 범위와 남은 차단 항목의 우선 기준이다. 날짜가 더 이른 감사·회차
문서와 충돌하면 이 문서의 판정을 따른다. 과거 문서는 당시 패키지와 당시 실행 회차의 증거로만
보존한다.

## 활성 기준선

- 개발·실행·패키징 대상은 `src/MBN_STOCK_WEBVIEW.LegacyParityApp` 하나다.
- 루트 `MBN_STOCK_WEBVIEW.csproj`와 루트 `MainWindow*`/`Web`은 이전 비교 프로토타입이다.
  현행 솔루션과 기본 F5에서는 제외했으며, 연결된 과거 비교 테스트 정리 전까지 참고용으로 보존한다.
- 원본 `MBN_STOCK_N`은 비교 기준으로만 사용하며 계속 읽기 전용이다.
- 이 문서 외의 작업 기록, 날짜별 감사와 실행 회차 문서는 당시 증거다.

## 현재 결론

전체 이관은 기능·개발 검증 기준으로 거의 완료됐다. 없는 외부 제작 자산은 관련 action만
fail closed로 제한한 채 진행하고, 고객 배포는 사용자가 다시 결정할 때까지 현재 범위에서 보류한다.
기존 DB 재생목록은 활성 정의 23개/2,213행 모두 목록과 scene alias까지 로드하도록 복원했다.
최신 실제 DB 호환 감사에서는 1,617행을 fresh typed selection으로 복원했고, 남은 596행만
추정 없이 보류한다. 보류 사유는 KRX 테마 493행, NXT 테마 48행, 비교 시장 identity 유실
25행, unique closed mapper 없음 30행이다. 따라서 전체 목록은 열되, 개별 행의
payload·asset·송출 전 검증은 계속 분리한다.
2026-07-21에는 같은 원칙을 모든 동적 DB 목록에 적용해, 기존 행의 조회·편집과 실제 송출 가능
판정을 분리했다. 고정 개수 상한, 제목 trim, 중복 제목 제거, 활성 preview 전용 읽기 때문에 정상
legacy 행까지 숨기던 경로를 제거하고, 불완전한 개별 행만 표시·편집 또는 비활성 상태로 격리한다.

| 범위 | 현재 판정 | 검증 범위 |
|---|---|---|
| 원본 Scene 구현 | 완료 | builder 35/35, 실제 운영 runtime route 34개, 무alias 진단 전용 `s8086` 1개 |
| 원본 DB 연결 상태 감시 | 구현·자동 회귀 완료 | LegacyParityApp 시작 후 10초 간격으로 Oracle/MariaDB 상태를 확인하고 상태 전이 때만 native 로그를 남긴다. 운영자 입력·송출·자동 갱신이 시작되면 진단 조회를 취소하고 DB activity gate를 양보한다. 종료 시 monitor도 취소한다. 실제 DB 서버를 강제로 끊는 장애 주입은 하지 않았다. |
| 개발 MSIX 전체 UI/DB | **직전 패키지 실측 PASS · 최신 코드 물리 재검증 대기** | 등록 개발 패키지에서 실제 Windows 입력으로 UC1~UC7, GraphE, FSell, VIList, ThemeA, EList, PList 모달, 검색·키보드·컷/플레이리스트 drag를 검증했다. `readonly` 73, `graphe` 491, `catalog` 264, `screens` 664, `plist` 91, `dryrun-playout` 83 입력은 모두 PASS이고 blocked·state violation·warning은 전 회차 0이다. 그 뒤 즉시 행 선택, PROGRAM 중 미래 행 Space/전체 enabled 변경, ThemeA/UC6 빈 검색 전체 조회, 비교쌍 명시적 import와 설정 UI를 교정했으며 자동 검증은 통과했다. 이 변경을 포함한 새 AppX의 물리 입력·DB cleanup·로컬 상태 회차는 아직 최종 재실행 전이다. |
| 개발 Tornado2/PGM | **32/34 route 최신 실측 · s6001 4-action 실측 대기** | 최신 `LATEST-CORE-01`에서 `5001 → 선택 행 NEXT 5074 → Page NEXT → TAKE OUT` 6/6, 분할한 30-route 회차에서 30/30, 최신 `LATEST-PAGED-04`에서 5077/5088 경계 24/24를 실제 PGM으로 확인했다. 명령 실패·오류·retry·`OutcomeUnknown`은 0이다. `s6001`의 영상 비의존 4 action/18-stage workflow는 구현·static PASS지만 실제 PGM은 아직 실행하지 않았다. |
| PageN/장기 실행 경계 | **최신 결합 코드 실측 완료** | `LATEST-PAGED-04`에서 `5077` 6행을 1/20부터 20/20까지 실제 Page NEXT하고, 마지막 페이지에서 playlist NEXT로 `5088` 12행 1/20으로 전환했다. 이전 scene unload와 최종 TAKE OUT/UNLOAD/IDLE도 확인했다. `LATEST-CORE-01`의 5074 page 1→2도 포함한다. |
| runtime 폴더/자산 설정 | 구현·자동 회귀 완료 | 선택한 Cuts root는 active `.t2s` alias 45개와 필수 built-in asset 9개를 모두 요구한다. 외부 제작 asset 14개는 없어도 설정을 수용하되 영향 경로만 제한한다. 빈 파일·reparse·중간 junction·root 이탈은 거부한다. 폴더 picker 취소와 최신 AppX 물리 검증은 최종 재실행 대기다. |
| 자동 회귀 | 완료, 최종 합계 갱신 대기 | 마지막 전체 .NET solution 실행은 3,115/3,115였다. 그 뒤 GraphE storage compatibility, 즉시 선택, PROGRAM 미래 행 enabled, ThemeA/UC6 빈 검색, 설정 validator, 비교 importer와 s6001 staged workflow의 focused/static 검증도 통과했다. 전체 solution 합계는 최종 재실행 뒤 갱신한다. 직전 별도 스크립트는 LegacyParityWeb 127/127, WebPlayout JavaScript 424/424이고 Debug build/rebuild는 warning 0, error 0이다. |
| 고객 배포 MSIX | 현재 범위에서 보류 | 현재 결과는 unsigned 개발 패키지다. 고객용 version, Publisher, 서명 인증서, 업데이트 방식과 새 PC의 DB/Development Live 로컬 설정 배포안은 사용자가 배포 작업을 재개할 때 결정한다. |

## 2026-07-21~22 기존 DB 로드·편집 호환 재검수

실제 Oracle/MariaDB를 read-only로 다시 조회하고 직전 등록 개발 패키지를 DryRun으로 실행해
다음을 확인했다. 아래 목록 조회와 편집 화면 확인 중 DB write 및 Tornado2/PGM 명령은 0건이다.

| 화면/경로 | 실제 DB 및 패키지 결과 | 송출 경계 |
|---|---|---|
| 국내 종목/비교/VI | 빈 검색 4,599/4,599, `KODEX` 238/238 표시 | 선택한 typed identity만 사용 |
| 해외 비교 종목 | raw 1,490, 표시 1,474, 선택 가능 1,473, 이름 없음 16행 격리, 쉼표 직렬화가 모호한 1행은 표시하되 비활성 | 비활성 행은 선택·저장·송출 거부 |
| UC5 해외 | 업종 53, 종목 1,474와 이름 없음 16행 격리 | 업종은 이름뿐 아니라 input name·symbol·nation·FDTC exact identity 사용 |
| Theme/ThemeA | 전체 1,747(KRX 1,571/NXT 176), 경계 공백 제목과 중복 제목도 보존 | NXT preview가 빈 4개 테마는 목록에는 보이되 action 차단 |
| ThemeA 기존 편집 | `SB_ITEM` 원문 전체 읽기. KRX/NXT 교차 prefix 5/3행, 동일 순번 2그룹·4행 보존. 대표 중복순번 테마 14행과 후행 공백 제목 11행을 실제로 열어 확인 | 활성 종목 기반 strict preview는 송출용으로 별도 유지; 새로 추가한 종목만 current master 검증 |
| EList/전문가 | 전문가 6명, 추천 32행, 매수가 NULL 5행을 빈 값으로 보존 | NULL 매수가 포함 행은 편집 가능하지만 숫자 송출 전 차단 |
| FSell/VI 로컬 데이터 | `%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\OperatorData`의 개인·외국인·기관·VI발동 4파일이 authoritative 원본 `bin\Debug\Data`와 각각 length·SHA-256 exact equal | 미이관 파일이 아니며 현재 앱에서 사용 가능. 실제 파일은 Git/MSIX 밖에서 trusted 검사 유지 |
| GraphE | 4개 테이블 7,776행 모두 raw 조회·편집 가능. Revenue 1,960/1, Growth 1,114/5, Sales 2,329/20, OperatingProfit 2,323/24(strict-ready/deferred), 합계 strict-ready 7,726행·deferred 50행 | 원본 저장 의미와 같은 정수 공백·TAB, 분기명 후행 TAB 및 완전히 동등한 중복행을 수용한다. conflicting 중복과 실제 불완전 payload는 계속 차단한다. 기존 이름 기반 GraphE 재생목록 36행은 36/36 fresh materialization됐다. |
| PList | 정의 23개/2,213행 전체 로드, scene alias 2,213/2,213, whole-list reject 0. fresh selection 1,617, 보류 596 | 행별 fresh payload·asset·PGM 검증은 사용할 때 별도 수행 |

직전 패키지 실제 클릭 결과는 C# snapshot과 DOM 행 수가 모두 일치했고, 검수 전 편성표 58행은
끝까지 58행으로 유지됐다. ThemeA와 GraphE의 기존 원문을 단순 조회하거나 편집 화면에 여는 행위가
곧 송출 가능 승인을 뜻하지는 않는다.

## 2026-07-22 직전 등록 패키지 실제 입력 기준선

당시 등록된 Development Mode 패키지의 Web 자산과 핵심 DLL이 당시 빌드 산출물과 같은지 hash로
확인한 뒤 여섯 회차를 실행했다. 패키지 입력 도구에도 빌드 AppX와 등록 AppX가 다르면 시작 전에
fail closed하는 검사를 추가했다. 모든 회차는 앱을 정상 종료했으며, 종료 뒤 Tornado2 연결은 0이었다.
아래 결과는 유효한 직전 물리 입력 기준선이지만, 이후 교정 사항을 포함한 최신 AppX의 최종 물리
재검증 결과로 확대하지 않는다.

| 회차 | 실제 입력과 검사 | 결과 |
|---|---|---|
| `latest-readonly` | 73입력, outbound 29건, DB write 0, playout intent 0, 최종 playlist 3행 | PASS, blocked/violation/warning 0 |
| `latest-graphe` | 491입력, 5 화면 검사, 12 DB 검사, 승인 write 12건 | PASS, cleanup 확인, blocked/violation/warning 0 |
| `latest-catalog` | 264입력, ThemeA KRX/NXT와 EList 3 화면 검사, 11 DB 검사, 승인 write 7건 | PASS, cleanup 확인, blocked/violation/warning 0 |
| `latest-screens` | 664입력, UC1~UC7·GraphE·FSell·VI 등 15 화면/15 DB 검사, 승인 변경 22건 | PASS, cleanup 확인, blocked/violation/warning 0 |
| `latest-plist` | 91입력, create/save→fresh readback→delete/absence 3 DB 검사, 승인 write 3건 | PASS, cleanup 확인, blocked/violation/warning 0 |
| `latest-dryrun-playout` | 83입력, 3행 중 선택 행 기준 NEXT, drag feedback/state, PROGRAM 중 컷 선택, 안전한 tail double-click append | PASS, DB write 0, Tornado2 연결 0, blocked/violation/warning 0 |

`latest-dryrun-playout`의 식별 결과는 staged `legacy-stock-00000002`, 선택
`legacy-stock-00000003`, NEXT `legacy-stock-00000001`, 안전 append
`legacy-stock-00000004`였다. PROGRAM 뒤 컷 선택은 0번이고 playlist는 3행에서 4행으로 정확히
한 행만 늘었다.

## 실제 PGM 검증 경계

- 최신 결합 코드의 `MBNWEB-20260722-LATEST-CORE-01`에서 `5001 → 5074 playlist NEXT →
  5074 Page NEXT → TAKE OUT/IDLE` 6/6을 검증했다. 2026-07-11 Round H와
  `CORE5001-05`는 역사적 증거로만 보존한다.
- 이어서 외부자산에 의존하지 않는 30개 route를 순차 검증했다. 마지막 `5025` TAKE OUT 뒤
  `UNLOAD 1/1`, `FAILURE 0`, `ERROR 0`, 정확한 `IDLE`을 확인했다.
- 같은 30개를 구 프로그램과 신규 프로그램에서 동일한 저장 편성표 순서와 실제 포인터 입력으로
  각각 실행했다. 신규는 UI 상태 증거 120개와 PROGRAM 직후 PGM 화면 30개를 남겼고,
  장면별 합산은 LOAD 30/30, PREPARE 56/56, PLAY 56/56, UNLOAD 30/30,
  `FAILURE=0`, `ERROR=0`이다. 구 프로그램은 이번 현재 데이터 회차에서 PGM 오류 없는 PROGRAM
  11개, PGM 오류 포함 4개, 데이터·매핑 차단 15개였다. 오류 없는 11개의 mutation 대조에서는
  8개가 동등했고, 2개는 저장 기간 제목 복원 차이, 1개는 베이시스·선물 갱신 누락이었다. 상세 판정은
  [`LEGACY_NEW_PLAYOUT_COMPARISON_20260719.md`](LEGACY_NEW_PLAYOUT_COMPARISON_20260719.md)에 고정했다.
- `5032`는 authoritative asset에 실제로 존재하지 않는 장식 오브젝트와 `pattern` 자산을 보내지
  않도록 계약을 교정한 뒤 다시 검증했다. 선물 좌·우 plate가 정상 표시되고 관련 명령 실패는 0이다.
- 최초 `5077` 경계 검증에서 실제 데이터 120건임에도 행의 page count가 `1/1`로 고정되는 결함을
  발견했다. 첫 PREPARE/TAKE IN 전에 전체 PageN 행을 read-only preflight하여 `1/N`을 고정하도록
  수정했다. 최신 결합 코드의 `MBNWEB-20260722-LATEST-PAGED-04`에서 `5077` 20페이지 전체,
  `5088` 전환, 이전 scene unload와 최종 TAKE OUT/UNLOAD/IDLE을 24/24로 재검증했다. 결함이
  있던 최초 실행과 이전 `PAGED-01`은 최신 승인 근거로 사용하지 않는다.
- `s6001` 중 국가 영상이 필요 없는 두바이유·WTI·브렌트유·금 4 action은 global
  `images\주유기merge.png`, `images\35752913_l.jpg`를 고정 검증하는 18-stage staged workflow로
  구현했고 static audit가 통과했다. 실제 PGM 회차는 아직 실행 전이므로 성공 증거에 포함하지 않는다.
- `s5006`의 큐브 배경 1개와 `s6001`의 국가 영상 13개는 asset preflight에서 관련 action만
  fail closed한다. 이 14개가 현재 남은 외부 제작 자산 경계다.

로컬 상세 증거는 다음 위치에 있다.

- [`최신 5001/5074 Core PGM`](../artifacts/pgm-evidence/MBNWEB-20260722-LATEST-CORE-01)
- [`30 route 0~19 PGM`](../artifacts/pgm-evidence/MBNWEB-20260722-THIRTY-02)
- [`8001 known-state TAKE OUT`](../artifacts/pgm-evidence/MBNWEB-20260722-RECOVERY8001-01)
- [`30 route 20~29 PGM`](../artifacts/pgm-evidence/MBNWEB-20260722-THIRTY20-29-01)
- [`최신 5077/5088 20-page PGM`](../artifacts/pgm-evidence/MBNWEB-20260722-LATEST-PAGED-04)
- [`구/신규 30개 송출 비교`](LEGACY_NEW_PLAYOUT_COMPARISON_20260719.md)
- [`직전 read-only 입력 PASS`](../artifacts/package-input-smoke/legacy-package-input-20260721T221024787Z-latest-readonly.json)
- [`직전 GraphE 입력/DB PASS`](../artifacts/package-input-smoke/legacy-package-input-20260721T221122292Z-latest-graphe.json)
- [`직전 ThemeA/EList 입력/DB PASS`](../artifacts/package-input-smoke/legacy-package-input-20260721T221252795Z-latest-catalog.json)
- [`직전 전체 화면/DB PASS`](../artifacts/package-input-smoke/legacy-package-input-20260721T221352946Z-latest-screens.json)
- [`직전 PList 입력/DB PASS`](../artifacts/package-input-smoke/legacy-package-input-20260721T221553250Z-latest-plist.json)
- [`직전 DryRun 송출 입력 PASS`](../artifacts/package-input-smoke/legacy-package-input-20260721T221635626Z-latest-dryrun-playout.json)

`artifacts`의 개발 장비 증거에는 로컬 실행 상태가 포함될 수 있으므로 고객 MSIX나 Git 배포물에
넣지 않는다.

## 현재 코드 작업과 분리된 외부 항목

### 1. 제작 자산

- `s5006\Video\큐브배경.vrv`
- `s6001` 국가 영상 13개

현재 authoritative 원본 Cuts에도 없다. 자산 없이 진행한다는 사용자 결정에 따라 제공 전에는
관련 action만 안전하게 차단하며, 이는 현재 작업 전체의 차단 사유가 아니다. `s6001`의 영상
비의존 4 action은 별도 실제 PGM 검증 대상으로 계속 진행한다. 나중에 자산을 받으면 trusted
root·빈 파일·reparse·경로 이탈 검사를 통과시킨 뒤 `s5006`과 국가 영상 action을 실제 PGM에서 검증한다.

### 2. 기존 플레이리스트 데이터 정합성

현행 operator 경로는 총 2,213행을 모두 DB에서 읽어 화면과 스케줄에 복원하고, 2,213행 모두
기존 scene alias로 식별한다. 직전 개발 패키지에서도 `DB 불러오기 → 첫 목록 → 불러오기`를 실제
마우스로 실행해 58행, 팝업 0, scene 미식별 0을 확인했다. 이 결과는 목록 로드/alias 복원 근거다.

2026-07-12 감사의 `1,603 selectionMapped / 610 보류`는 당시 raw 저장값에서 현재 DB identity를
fresh하게 다시 증명한 역사적 수치다. 최신 실제 DB 재감사에서는 GraphE 36행을 모두 fresh
materialization하여 `1,617 복원 / 596 보류`로 갱신됐다. 596행은 KRX 테마 493행, NXT 테마
48행, 비교 시장 identity 유실 25행, unique closed mapper 없음 30행이다. 목록 로드 차단으로
해석하지 않으며, 이름이나 유사 scene으로 추정하지 않는다.

원본 `종목비교.dat` 8쌍을 현재 로컬 순서 뒤에 중복 없이 병합하는 명시적 importer도 구현했다.
원본 파일은 고정된 trusted path에서 읽기 전용으로 열고 8쌍을 모두 resolve한 뒤에만 atomic하게
저장하며, 실패 시 현재 파일을 보존한다. 실제 최신 AppX에서 `현재 1쌍 + 원본 8쌍 = 9쌍`과 두 번째
실행의 `추가 0`을 확인하는 로컬 상태 smoke는 아직 실행 전이다.

### 3. 고객 배포

현재 작업 범위에서는 보류한다. 사용자가 배포를 재개하면
고객용 version, Publisher, 서명 인증서, 인증서 보관·갱신 절차, 업데이트 방식, 새 PC의 DB 및
Development Live 로컬 설정 배포 방식이 확정돼야 한다. Release/default `DryRun`, scene/path
allowlist, vendor hash, STA 직렬화와 대상 identity 검사는 그대로 유지한다.

## 완료 조건

최신 AppX의 전체 물리 입력/DB cleanup/설정·비교 import 로컬 상태 재검증, `s6001` 영상 비의존
4 action의 실제 PGM 검증, 기존 보류 행의 payload/asset/PGM 경계 판정을 마치면 현재 개발 장비의
대체 운영 기준선을 확정한다. 외부 제작 자산 14개가 없는 action은 제공 전까지 명시적으로 차단한
상태가 정상 기준이다. 고객 서명 MSIX의 clean 설치·업데이트·새 PC 설정 검증은 사용자가 배포를
재개할 때 별도 완료 조건으로 적용한다.
