docs: record completed Tornado playout parity

This commit is contained in:
2026-07-11 15:33:06 +09:00
parent fa0eae7b61
commit d2e16bf0c2
5 changed files with 111 additions and 40 deletions

View File

@@ -1,8 +1,8 @@
# 35개 Scene 동등성 완료 매트릭스
기준 시각은 2026-07-10이다. 원본 `C:\Users\MD\source\repos\MBN_STOCK_N`은 읽기 전용으로만 분석했으며, 이 문서 작업에서도 원본 파일을 수정하지 않았다. 원본 35개 builder의 파일 해시는 [`legacy-scene-source-hashes.json`](legacy-scene-source-hashes.json), 원본 구조 기준선 검사는 [`Test-LegacySceneBaseline.ps1`](../scripts/Test-LegacySceneBaseline.ps1)에 있다.
기준 시각은 2026-07-11이다. 원본 `C:\Users\MD\source\repos\MBN_STOCK_N`은 읽기 전용으로만 분석했으며, 이 문서 작업에서도 원본 파일을 수정하지 않았다. 원본 35개 builder의 파일 해시는 [`legacy-scene-source-hashes.json`](legacy-scene-source-hashes.json), 원본 구조 기준선 검사는 [`Test-LegacySceneBaseline.ps1`](../scripts/Test-LegacySceneBaseline.ps1)에 있다.
이 문서에서 **구현 완료**는 DTO → mutation builder, 실제 데이터 loader, playlist selection resolver 또는 명시적 runtime route, 자동 테스트가 모두 존재한다는 뜻이다. **동등성 완료**는 여기에 실제 데이터와 승인된 Tornado2/PGM 검증까지 통과해야 한다. 따라서 현재 전체 목표는 아직 완료가 아니다.
이 문서에서 **구현 완료**는 DTO → mutation builder, 실제 데이터 loader, playlist selection resolver 또는 명시적 runtime route, 자동 테스트가 모두 존재한다는 뜻이다. **자동 동등성 완료**는 원본 35개 builder의 source hash/inventory 기준선을 고정하고, 원본 구현에서 도출한 오브젝트·mutation·호출 순서·45개 alias·PageN 기대값을 새 구현의 매트릭스와 자동 suite로 검증했다는 뜻이다. 실행 중인 구 구현과 새 구현을 같은 입력으로 직접 호출해 의미를 대조하는 comparator가 있다는 뜻은 아니다. **실제 Tornado 검증**은 승인된 scene과 회차에만 적용한다. 현재 마이그레이션 기준선은 완료됐지만 실제 PGM 증거를 승인되지 않은 나머지 scene으로 확대 해석하지 않는다.
## 현재 판정
@@ -11,15 +11,13 @@
| 원본 inventory와 hash 기준선 | 완료 | 35/35 builder, 원본 기준선 스크립트 35/35 |
| DTO와 mutation builder | 완료 | registry가 정확히 35개 builder를 발견하고 catalog와 1:1 대조 |
| loader와 runtime route | 완료 | MainForm 도달 가능 builder 34개, active alias 45개를 fail-closed route로 등록; `s8086`은 원본과 같이 무alias 진단 전용 |
| 자동 테스트 | 완료 | 최신 전체 재검증에서 Core Debug/Release x64 각각 779/779, Playout 각각 355/355, Infrastructure 각각 65/65, Web safety 12/12 통과. 테스트 추가에 따라 개수는 달라질 수 있으며 핵심 판정은 각 suite의 실패 0건이다. |
| Visual Studio 2026 빌드 | 완료 | Debug/Release x64 빌드 성공 |
| Release x64 MSIX | 완료 | trusted 개발 MSIX 생성·서명 검증·x64 설치·package context 실행 성공. 실제 DB DryRun에서 `5001 PREPARE → fresh TAKE IN → timer refresh → 5074 playlist NEXT → Page NEXT → TAKE OUT`과 5074의 `1/20`~`20/20`, 마지막 `END OF PLAYLIST`/NEXT 비활성, 편집 잠금 해제를 확인 |
| 실제 데이터 전체 장면 smoke | 완료 | 34개 도달 가능 builder 전체 통과: 33개 Oracle/MariaDB loader와 `s5025` trusted 외부 CP949 파일. 무alias `s8086` diagnostic도 통과했고 실제 Oracle/MariaDB query 55건이 모두 성공했다. |
| 이번 마이그레이션의 실제 Tornado2/PGM | **부분 실행·실패 회차 종료** | `MBNWEB-20260711-A`에서 CONNECT와 `PREPARE 5001/page 1`은 성공했으나 fresh TAKE IN의 Oracle 조회가 `DATABASE_UNAVAILABLE`로 명확히 실패했다. K3D `PLAY`는 발생하지 않았고 Page/playlist NEXT와 timer refresh는 실행하지 않음 |
| 자동 테스트 | 완료 | 소스 `fa0eae7b61f57f134dfd30ebf1e59e9cc2cccfc5`: Core 790/790, Playout 374/374, Infrastructure 65/65가 Debug/Release x64에서 각각 통과했고 Web safety 12/12, 원본 baseline 35/35도 통과 |
| Visual Studio 2026 빌드 | 완료 | MSBuild `18.7.8` Debug/Release x64 및 앱 패키지 빌드 성공 |
| Release x64 MSIX | 완료 | 서명·설치·내용 감사와 package-context 실행 통과. SHA-256 `D51E8CB637860D9F0377AEE6FF691D7D954BA0FF7E30B1AB65443DA153BC5429`; packaged `DryRun`에서 `5001 PREPARE → fresh TAKE IN → 자동 refresh 1회 → 5074 playlist NEXT → Page NEXT → TAKE OUT`을 확인하고 전체 PageN 경계는 자동 테스트로 확인 |
| 실제 데이터 전체 장면 smoke | 완료 | 34개 도달 가능 builder 전체 통과: 33개 Oracle/MariaDB loader와 `s5025` trusted 외부 CP949 파일. 무alias `s8086` diagnostic도 통과했고 실제 Oracle/MariaDB query 55/55가 성공했다. |
| 이번 마이그레이션의 실제 Tornado2/PGM | **승인 범위 완료** | 계획 SHA-256 `55C7755C2F874B4B012239117D4AB717BBCE194E7DCC8DA9B0E40D094FF8CA19` `MBNWEB-20260711-H`에서 `5001 → 자동 refresh 1회 → 5074 page 1 → page 2 → TAKE OUT`을 PGM과 Network Monitoring으로 함께 확인. 최종 검은 화면, retry 0, `OutcomeUnknown = false` |
과거 고정 runner로 수행한 `5001 → 5006` PGM 왕복은 K3D 연결과 기본 load/play/stop 경로의 증거일 뿐이다. 35개 builder, 실제 DB mutation, Page NEXT와 현재 WebView workflow의 동등성 증거로 재사용하지 않는다.
`MBNWEB-20260711-A`는 장애 복구 절차의 실제 증거다. Network Monitoring에서 `HELLO`, 5001의 `LOAD_SCENE`/transaction/mutation/`SCENE_PREPARE` 성공을 확인했고 PREPARE 뒤 PGM은 검은 화면을 유지했다. TAKE IN은 fresh Oracle 조회 단계에서 명확히 거부되어 `PLAY`가 없었으며 재시도하지 않았다. 승인된 `TAKE OUT All` 한 번으로 `STOPAL``UNLOAD_SCENE 5001` 성공을 확인한 뒤 `BYE`로 종료했고 PGM은 계속 검은 화면이었다. 직후 독립 DB probe에서는 Oracle unhealthy/MariaDB healthy였고 Oracle DNS와 TCP endpoint는 도달 가능했으며, 회차 종료 뒤 전체 55-query 스모크는 Oracle/MariaDB 모두 다시 통과했다. 이 실패 회차는 동등성 완료 증거가 아니므로 새 동결 계획·새 회차 승인 뒤 전체 시퀀스를 다시 검증해야 한다.
Round H의 실제 Network Monitoring 합계는 `SCENE_PREPARE 5001 = 3`, `SCENE_PREPARE 5074 = 2`, `PLAY = 4`, `SCENE_PLAYED = 4`, `FAILURE = 0`, `ERROR = 0`이다. PGM은 5001 데이터, 5074의 page 1과 page 2를 순서대로 렌더링했고 TAKE OUT 뒤 검은 화면이 됐다. 이 증거는 승인된 두 scene에만 유효하다. 과거 실패 회차와 고정 runner는 장애 복구·기본 연결 근거로 보존하되 Round H의 동등성 근거를 대신하거나 확장하지 않는다.
## 표기
@@ -46,6 +44,7 @@ Mutation 약어는 실제 COM 메서드를 Web 입력에 노출하지 않는 COM
- `FILE-P`: `s5025`의 trusted 외부 CP949 수동 파일 → DTO → mutation preflight가 통과했다. 실제 파일과 디렉터리는 계속 Git 밖에 둔다.
- `DB-DP`: 원본 MainForm에서 도달하지 않는 `s8086` diagnostic 조회와 mutation preflight가 통과했다. 이 결과로 runtime alias를 만들지는 않는다.
- `TOR-W`: 이번 마이그레이션 runtime으로 해당 scene을 실제 Tornado2/PGM에서 검증하지 않았다. 회차 승인 전에는 실행하지 않는다.
- `TOR-H`: Round H의 승인된 WebView Live 회차에서 PGM 화면과 Network Monitoring을 함께 검증했다.
- `TOR-NA`: active alias가 없어 운영 송출 대상이 아니다.
## 자동 테스트 묶음
@@ -69,7 +68,7 @@ Mutation 약어는 실제 COM 메서드를 Web 입력에 노출하지 않는 COM
| Builder / alias / page | 원본 기능 | 새 builder → loader → resolver/route | mutation | 자동 테스트 | 실제 데이터 | 실제 Tornado |
|---|---|---|---|---|---|---|
| `s5001` / `5001`, `N5001` / — | 국내·NXT·해외 지수, 환율, 업종, 종목 단일 시세와 등락 표식 | `S5001SceneMutationBuilder``S5001SceneDataLoader``LegacyParameterizedSceneRequestResolver` | `V, Vis, A` | `T-PARAM` 통과 | `DB-P` | `TOR-W` |
| `s5001` / `5001`, `N5001` / — | 국내·NXT·해외 지수, 환율, 업종, 종목 단일 시세와 등락 표식 | `S5001SceneMutationBuilder``S5001SceneDataLoader``LegacyParameterizedSceneRequestResolver` | `V, Vis, A` | `T-PARAM` 통과 | `DB-P` | `TOR-H` (`5001`) |
| `s5006` / `5006` / — | 국내·NXT 종목 현재·시가·고가·저가와 비율, 등락 상태, 큐브 배경 영상 | `S5006SceneMutationBuilder``S5006DomesticSceneDataLoader`/`S5006NxtSceneDataLoader` → market 직접 route | `V, Vis, C, BgV` | `T-PANEL` 통과 | `DB-P`; `Video\큐브배경.vrv` 외부 자산 누락 | `TOR-W` |
| `s5011` / `5011` / — | 국내·NXT 종목 시세, 액면가, 자본금, 시가총액, 순위 | `S5011SceneMutationBuilder``S5011SceneDataLoader` → branch 직접 route | `V, Vis, C` | `T-PANEL` 통과 | `DB-P` | `TOR-W` |
| `s5016` / `5016` / — | 미국·중화권·유럽·아시아 지수와 채권·환율·원자재 3열 panel | `S5016SceneMutationBuilder``S5016SceneDataLoader` → closed target 직접 route | `V, Vis` | `T-PANEL` 통과 | `DB-P` | `TOR-W` |
@@ -81,7 +80,7 @@ Mutation 약어는 실제 COM 메서드를 Web 입력에 노출하지 않는 COM
| `s5029` / `5029` / — | 두 종목 candle·수익률 비교와 두 path-shape | `S5029SceneMutationBuilder``S5029SceneDataLoader``ComparisonAndYieldLegacyRequestResolver` | `V, Vis, Pos, Shape` | `T-COMP` 통과 | `DB-P` | `TOR-W` |
| `s5032` / `8018`, `8032`, `5032` 중 선물 조건 / — | 선물을 포함한 좌·우 두 항목 plate | `S5032SceneMutationBuilder``S5032SceneDataLoader``LegacyParameterizedSceneRequestResolver` | `V, Vis, A` | `T-PARAM` 통과 | `DB-P` | `TOR-W` |
| `s5037` / `5037` / — | 국내 종목 현재가와 매수·매도 거래원별 수량 | `S5037SceneMutationBuilder``S5037SceneDataLoader``LegacyGridMarketSceneRequestResolver` | `V, Vis` | `T-GRID` 통과 | `DB-P` | `TOR-W` |
| `s5074` / `5074` / 5 | Oracle/MariaDB/DataManager 계열의 최대 5행 시세·수익률 목록 | `S5074SceneMutationBuilder``S5074SceneDataLoader` → typed paged 직접 route | `V, Vis, A` | `T-PAGED` 통과 | `DB-P` | `TOR-W` |
| `s5074` / `5074` / 5 | Oracle/MariaDB/DataManager 계열의 최대 5행 시세·수익률 목록 | `S5074SceneMutationBuilder``S5074SceneDataLoader` → typed paged 직접 route | `V, Vis, A` | `T-PAGED` 통과 | `DB-P` | `TOR-H` (page 1/2) |
| `s5076` / `5076` / — | 주요매출 구성, 기준일, 항목 비율과 누적 원형 각도 | `S5076SceneMutationBuilder``S5076SceneDataLoader` → subject 직접 route | `V, Vis, Angle` | `T-FOUND` 통과 | `DB-P` | `TOR-W` |
| `s5077` / `5077` / 6 | Oracle/MariaDB/DataManager 계열의 최대 6행 시세·수익률 목록 | `S5077SceneMutationBuilder``S5077SceneDataLoader` → typed paged 직접 route | `V, Vis, A` | `T-PAGED` 통과 | `DB-P` | `TOR-W` |
| `s5078` / `5078` / — | 미국·국내 섹터지수 값과 양·음 막대 크기 | `S5078SceneMutationBuilder``S5078SceneDataLoader``ChartLegacySceneRequestResolver` | `V, Vis, Scale` | `T-CHART` 통과 | `DB-P` | `TOR-W` |
@@ -135,8 +134,9 @@ TAKE IN은 PREPARE 때의 오래된 DTO를 그대로 재생하지 않는다. 원
- `s5088`의 NXT 인덱스는 비교와 조회 모두 `i + pageIndex * 12`를 사용한다.
- 현재 항목에 다음 page가 있으면 operator Page NEXT는 playlist index를 유지하되 원본 `Next_Scene(0)`처럼 다음 page 데이터를 조회하고 새 scene을 `LoadScene` → transaction mutation → `QueryVariables``EndTransaction``Prepare(10)``Play(10)`한다. 이 경로는 `GetPlayingScene` in-place refresh가 아니다.
- 마지막 page면 다음 활성 playlist 항목으로 이동한다. 비활성 항목은 원본처럼 앞으로 건너뛰며 끝에서 wrap하지 않는다.
- 모든 operator command는 기존 refresh timer를 먼저 멈춘다. TAKE IN과 playlist NEXT 성공 뒤에는 해당 cut의 원본 `m_time`으로 첫 timer를 시작하고, 첫 성공 뒤부터 3초 간격으로 갱신한다. Page NEXT 성공 뒤에는 timer를 다시 시작하지 않는다.
- timer refresh는 current entry/page를 fresh DB DTO로 다시 만든 뒤, 원본 `timer1_Tick`의 K3D 호출 순서인 `Play(10)``GetPlayingScene(10)` → transaction mutation → `QueryVariables``EndTransaction``Prepare(10)``Play(10)`으로 on-air scene을 갱신한다.
- 원본 timer는 TAKE IN과 playlist NEXT 뒤 반복되며 첫 `m_time` 이후 3초 주기로 계속 실행된다. 새 runtime도 반복 갱신을 유지하지만, 이전 tracked `Play``OnScenePlayed` callback을 drain한 뒤에야 첫 `m_time` 또는 3초의 **전체 cooldown**을 시작한다. 이는 callback 대기와 delay가 겹쳐 operator window가 사라지는 일을 막는 의도적 안전 적응이다. 모든 operator command는 현재 epoch를 먼저 중단하고 Page NEXT 뒤에는 refresh를 재시작하지 않는다.
- 원본 `timer1_Tick`에는 mutation 전 선행 `Play(10)``Prepare` 뒤 후행 `Play(10)`이 모두 있다. 마이그레이션은 불완전한 `GetPlayingScene` proxy 대신 retained on-air scene에 fresh DTO mutation을 적용하고 `BeginTransaction mutation → QueryVariables → EndTransaction → Prepare(10) → tracked Play(10)` 한 번만 보낸다. 선행 replay를 생략한 것은 callback 추적 없이 PLAY를 중복시키지 않기 위한 명시적 안전 차이이며 Round H의 정확한 PLAY/callback 4회 예산에 반영됐다.
- refresh CTS와 공개 상태는 atomic epoch로 결합한다. `Replace`/`Stop`/조건부 update/completion이 같은 lock에서 generation을 확인하므로 취소된 이전 loop가 `active`, `NextAt`, success 또는 fault를 새 loop나 중단 상태 위에 다시 쓰지 못한다.
## WebView 동등성 및 안전 상태
@@ -158,13 +158,13 @@ TAKE IN은 PREPARE 때의 오래된 DTO를 그대로 재생하지 않는다. 원
운영·장애 복구·승인 절차는 [`PLAYOUT_OPERATIONS.md`](PLAYOUT_OPERATIONS.md)를 따른다.
## 남은 완료 조건
## 완료 판정과 실제 송출 범위
다음 항목이 끝나기 전에는 이 문서의 전체 상태를 동등성 완료로 바꾸지 않는다.
35개 builder, 45개 active alias, DTO/mutation, 실제 DB 55-query, 5·6·12행 PageN 경계와 마지막 페이지, Debug/Release x64 suite와 packaged `DryRun`은 완료 기준을 충족했다. Round H는 설치된 Release x64 MSIX의 WebView workflow로 승인된 `5001``5074`에 대해 PREPARE → fresh TAKE IN → 자동 refresh → playlist NEXT → Page NEXT → TAKE OUT을 실제 Tornado2에서 완료했다.
1. 승인된 외부 asset root에 `s5006``Video\큐브배경.vrv`가 제공돼야 한다.
2. 설치된 Release x64 MSIX의 WebView workflow로 승인된 테스트 scene에 대해 PREPARE → fresh TAKE IN → Page NEXT/playlist NEXT → timer refresh → TAKE OUT을 실행해야 한다.
3. 같은 회차의 Tornado2 Network Monitoring 명령/응답과 PGM 데이터·페이지·종료 화면을 함께 보존하고 비교해야 한다.
4. timeout, `OutcomeUnknown`, refresh fault, callback/연결 장애 복구 절차를 실제 검증 결과에 적용하고 운영자가 판정해야 한다.
이 완료 판정에는 다음 범위 제한이 있다.
실제 DB/CP949 통합 검증과 자동 suite는 완료됐고 회차 종료 뒤 DB 스모크도 다시 통과했다. 다만 첫 WebView Live 회차는 fresh TAKE IN 전 Oracle 장애로 안전하게 종료됐으므로, 새 회차에서 TAKE IN → timer refresh → playlist/Page NEXT → TAKE OUT 전체를 통과하기 전까지 동등성 완료로 판정하지 않는다.
1. 실제 Tornado2/PGM 화면 증거는 `5001``5074` page 1/page 2뿐이다. 다른 builder의 실제 송출은 해당 scene과 자산을 묶은 새 계획·승인이 필요하다.
2. `s5025`는 승인된 trusted 외부 CP949 파일이 필수이며 파일·경로는 Git과 MSIX에 포함하지 않는다.
3. `s5006`의 background video 등 외부 asset이 필요한 scene은 승인된 asset root가 준비돼야 실제 송출할 수 있다.
4. timeout, `OutcomeUnknown`, refresh fault 또는 callback/연결 장애가 발생한 회차에서는 동일 명령을 반복하지 않고 [`PLAYOUT_OPERATIONS.md`](PLAYOUT_OPERATIONS.md)의 복구 절차를 적용한다.