Migrate remaining legacy operator workflows

This commit is contained in:
2026-07-12 05:39:27 +09:00
parent ffb8f43c19
commit a01836a2d7
132 changed files with 20566 additions and 720 deletions

View File

@@ -6,6 +6,8 @@
이 저장소의 작업과 자동 검증은 실제 PGM 출력 또는 라이브 `TAKE IN`을 허가하지 않습니다. `Test` 검증은 PGM과 분리된 전용 테스트 인스턴스, 테스트 출력 채널 및 허용 목록에 든 테스트 씬을 모두 확인한 뒤에만 수행합니다. `Live`는 운영 책임자의 명시적인 회차별 허가 없이는 사용하지 않습니다.
이 문서의 adapter·builder·DryRun 완료 표현은 화면/계약 구현 범위다. 운영 DB-W, 외부 asset readiness, 기존 데이터 복원과 장면별 실제 PGM은 별도 증거가 있어야 한다. 현재 미적용·적용 중·외부자산 필요 항목은 [`LEGACY_FEATURE_AUDIT.md`](LEGACY_FEATURE_AUDIT.md)를 따른다.
## 확인된 x64 COM 등록
현재 개발 장비에서 확인할 등록 기준은 다음과 같습니다.
@@ -94,7 +96,7 @@ SDK가 기본 위치에 없다면 x64 SDK의 `TlbImp.exe` 절대 경로를 `-Tlb
| `outputChannel` | 확인된 전용 출력 채널. `null`은 안전한 미설정 상태 |
| `layoutIndex` | 씬 플레이어 layout 위치 |
| `legacySceneFadeDuration` | 원본 `ComboDi.SelectedIndex`에 대응하는 fade. 기본값 6, 허용 범위 0~60 |
| `legacySceneBackgroundKind` | trusted 공통 배경 `None`, `Texture`, `Video`; Web에서 변경할 수 없음 |
| `legacySceneBackgroundKind` | trusted 공통 배경 `None`, `Texture`, `Video`; Web은 임의 경로를 보내지 않고 F2/F3가 native picker/toggle을 호출한다. 현재 picker는 `sceneDirectory` 내부만 허용하므로 원본의 sibling `배경` root와는 아직 동등하지 않음 |
| `legacySceneBackgroundAssetPath` | `sceneDirectory` 아래의 상대 asset. 경로 탈출·reparse·누락 파일은 DryRun에서도 거부 |
| `legacySceneBackgroundVideoLoopCount`, `legacySceneBackgroundVideoLoopInfinite` | 공통 video 배경의 bounded loop 설정 |
| `testProcessWindowTitlePattern` | 전용 테스트 인스턴스만 식별하는 창 제목 패턴 |
@@ -339,12 +341,20 @@ CLI용 Test JSON은 위처럼 앱 기본 경로인 `playout.local.json`과 다
3. 잘못된 설정 또는 엔진 부재가 앱 종료가 아니라 연결 상태와 안전한 오류 메시지로 표시됩니다.
4. x64 MSIX를 설치해도 같은 dry-run 흐름이 동작합니다.
최종 서명 Release x64 MSIX를 설치한 package context에서 실제 Oracle/MariaDB를 읽는 `DryRun` 검증을 완료했습니다. Web catalog 35개(34개 송출 가능), DB 상태 2/2 정상, alias `5001`/`N5001`, fade 6, mutation preview와 asset 경로 비노출을 확인했습니다. 이어 `5001 PREPARE → fresh TAKE IN → callback drain 뒤 full 2초 cooldown의 자동 refresh → 5074 playlist NEXT → 같은 entry/scene의 Page NEXT`를 수행했고, 5074 `page 1/20 → page 2/20` 전환과 Page NEXT 뒤 refresh 정지를 확인했습니다. 5·6·12개 단위, 최대 20페이지, partial/마지막 page의 clear·hide, `isLastPage`, `END OF PLAYLIST`와 NEXT 비활성 경계는 원본에서 도출해 고정한 자동 테스트로 검증했습니다. TAKE OUT 뒤에는 scene/refresh가 정리되고 playlist 편집 잠금이 해제되었습니다. 전 과정의 안전 배지는 `DRY RUN · PROGRAM 차단`이었고 COM/KTAP/Tornado2 연결은 발생하지 않았습니다.
최종 서명 Release x64 MSIX를 설치한 package context에서 실제 Oracle/MariaDB를 읽는 `DryRun` 검증을 완료했습니다. Web catalog 35개(34개 runtime route 보유), DB 상태 2/2 정상, alias `5001`/`N5001`, fade 6, mutation preview와 asset 경로 비노출을 확인했습니다. 34개 runtime route가 모두 외부 asset까지 준비됐다는 뜻은 아니다. 이어 `5001 PREPARE → fresh TAKE IN → callback drain 뒤 full 2초 cooldown의 자동 refresh → 5074 playlist NEXT → 같은 entry/scene의 Page NEXT`를 수행했고, 5074 `page 1/20 → page 2/20` 전환과 Page NEXT 뒤 refresh 정지를 확인했습니다. 5·6·12개 단위, 최대 20페이지, partial/마지막 page의 clear·hide, `isLastPage`, `END OF PLAYLIST`와 NEXT 비활성 경계는 원본에서 도출해 고정한 자동 테스트로 검증했습니다. TAKE OUT 뒤에는 scene/refresh가 정리되고 playlist 편집 잠금이 해제되었습니다. 전 과정의 안전 배지는 `DRY RUN · PROGRAM 차단`이었고 COM/KTAP/Tornado2 연결은 발생하지 않았습니다.
WebView 상태 wire는 `Disconnected`, `Connecting`, `Connected`, `Reconnecting`, `Faulted`, `OutcomeUnknown` 등 native connection state를 별도로 전달합니다. Web catalog는 35개 builder와 도달 가능한 45개 alias, row별 `enabled`를 보존하고 PREPARE 성공 뒤 playlist snapshot을 freeze합니다. pending command, `OutcomeUnknown`과 timeout quarantine 중에도 snapshot 편집 잠금을 유지합니다. native status의 current entry/builder/page size/current rows/last-page와 bounded preview가 authoritative 값이며 asset path는 preview에서 숨깁니다. refresh active/next/last-success/fault도 전달하고 refresh fault는 TAKE OUT 외 mutation 명령을 막습니다. 성공한 TAKE OUT 뒤에는 전용 refresh error marker만 reset하며 다른 unknown latch를 지우지 않습니다. `OutcomeUnknown`과 timeout은 `retryable: false`이며 오류 창을 닫아도 native 잠금은 유지됩니다. 브라우저 응답 제한 시간은 검증된 native operation timeout에 5초 전달 여유를 더해 사용하며, 상관 응답이 오지 않으면 strict `ParseTimeoutQuarantine` 요청을 native에 보냅니다. MainWindow는 await 전에 process-lifetime latch를 세우고 vendor session을 quarantine하므로 WebView reload로도 해제되지 않습니다. 명령 진행 중 trusted navigation, reload 또는 WebView2 process failure로 JavaScript 상관관계가 사라지는 경우도 같은 native latch를 먼저 세웁니다. 늦은 응답이나 UI 재시도로 같은 명령을 다시 보내지 않으며 native 명령이 끝나면 authoritative status를 다시 게시합니다. NEXT는 원본의 `m_TakeIn` 조건처럼 on-air 장면이 있을 때만 native와 Web 양쪽에서 허용됩니다. Test on-air 배지는 실제 PROGRAM과 구분해 `TEST ON AIR`로 표시합니다.
On-air 표식이 남은 상태에서는 프로세스 감시, 연결 해제, 앱 종료 및 세션 재활용 경로도 SDK `Disconnect`를 호출하지 않습니다. 중앙 `ReleaseSessionAsync` 방어가 세션을 quarantine/abandon하고 결과를 불명확 상태로 승격하므로, 운영자는 먼저 성공한 `TAKE OUT`을 확인한 다음 정상 종료해야 합니다.
### 화면/계약 구현과 운영 동등성 경계
- PList raw restore와 manual descriptor 계약은 구현됐지만 기존 한국어 `DC_TITLE`/`LIST_TEXT`, GraphE·FSell·VI를 포함한 manual named save→fresh restore는 운영 DB에서 검증되지 않았다.
- ThemeA/EList의 expected identity와 응답 상관 계약은 구현됐지만 KRX/NXT·동명이름·코드 경계의 실제 create/replace/delete read-back은 검증되지 않았다.
- 원본 `종목비교.dat`, FSell, VI 파일을 패키지 private 저장소로 옮기는 one-time import는 구현되지 않았다.
- `s5006``Video\큐브배경.vrv``s6001` 해외지수 국가 영상 13개는 현재 승인 Cuts에 없으며, alias-only `Missing=0`은 asset-ready 증거가 아니다.
- GraphE·PList/AList·ThemeA·EList 운영 DB-W와 `5001`/`5074` 밖의 실제 PGM은 미검증이다. 아래 Round H 기록은 승인된 두 scene의 역사적 증거로만 보존한다.
승인 컷의 과거 load/play 경로와 현재 WebView 기반 Scene/PageN 데이터 동등성은 서로 다른 검증 범위입니다. 복합 mutation·페이지 계산·fresh TAKE IN·Page NEXT·timer refresh는 구현 및 자동/실데이터 검증을 마쳤으며 [원본 Tornado 송출 흐름 분석](LEGACY_PLAYOUT_ANALYSIS.md)과 [35개 Scene 매트릭스](SCENE_EQUIVALENCE.md)에 기록합니다. 첫 Live WebView 회차 `MBNWEB-20260711-A`의 DB 실패와 Round G의 refresh starvation은 모두 결과를 추정하거나 반복하지 않고 안전하게 종료했습니다. 수정된 Round H에서는 승인된 5001/5074 범위의 실제 TAKE IN, 자동 refresh, playlist/Page NEXT와 TAKE OUT을 Network Monitoring과 PGM에서 함께 완료했습니다. 이 결과를 나머지 scene의 실제 PGM 검증으로 확대하지 않습니다.
일반 앱과 정규 Test 경로의 실제 COM 스모크는 별도 테스트 인스턴스와 테스트 씬이 준비된 때에만 진행합니다. 위 안전 게이트를 독립적으로 재확인하고 `mode``Test`로 바꾼 뒤 테스트 모니터에서 `PREPARE → fresh TAKE IN → Page/playlist NEXT → timer refresh → TAKE OUT` 결과를 관찰합니다. 의도하지 않은 PGM/운영 출력 변화가 보이면 추가 명령을 중단합니다. native 결과가 명확하고 Gate A에 포함된 경우에만 TAKE OUT을 한 번 요청하며, timeout·`OutcomeUnknown`·`WEB_TIMEOUT`·refresh fault라면 앱 종료나 반대 명령으로 자동 롤백하지 않고 session을 quarantine한 채 운영자가 실제 출력 상태를 먼저 확인합니다.