docs: record completed Tornado playout parity
This commit is contained in:
@@ -339,16 +339,32 @@ CLI용 Test JSON은 위처럼 앱 기본 경로인 `playout.local.json`과 다
|
||||
3. 잘못된 설정 또는 엔진 부재가 앱 종료가 아니라 연결 상태와 안전한 오류 메시지로 표시됩니다.
|
||||
4. x64 MSIX를 설치해도 같은 dry-run 흐름이 동작합니다.
|
||||
|
||||
2026-07-10 최종 서명 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 → 최초 2초·이후 3초 timer refresh → 5074 playlist NEXT → 같은 entry/scene의 Page NEXT`를 수행했고 Page NEXT 뒤 refresh가 정지했습니다. 5074는 5개 단위로 `1/20`부터 `20/20`까지 순서대로 진행되어 마지막에 `isLastPage=YES`, `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개 송출 가능), 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 연결은 발생하지 않았습니다.
|
||||
|
||||
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`을 확인한 다음 정상 종료해야 합니다.
|
||||
|
||||
승인 컷의 과거 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`는 CONNECT와 PREPARE까지 성공했지만 fresh TAKE IN의 Oracle 조회가 PLAY 전에 명확히 실패해 STOPAL/UNLOAD/BYE로 안전하게 종료했습니다. 회차 종료 뒤 Oracle/MariaDB 전체 스모크는 다시 통과했습니다. 남은 단계는 새 package와 회차 승인을 받아 실제 TAKE IN, timer refresh, playlist/Page NEXT, TAKE OUT을 Network Monitoring과 PGM에서 함께 통과하는 것입니다.
|
||||
승인 컷의 과거 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한 채 운영자가 실제 출력 상태를 먼저 확인합니다.
|
||||
|
||||
### 2026-07-11 Round G/H 실제 PGM 검증
|
||||
|
||||
Round G `MBNWEB-20260711-G`는 5001 TAKE IN과 PGM 표시까지 성공했지만, 자동 refresh가 승인된 1회 예산을 넘어 연속 실행되는 `POST_TAKE_IN_AUTOMATIC_REFRESH_BUDGET_STARVATION` 경계에서 실패했습니다. 성공한 transaction/prepare 39회와 PLAY/callback 38회가 있었고 native FAILURE/ERROR는 0이었지만, `refreshLastSuccessAt`이 갱신되는 동안 `playCompletionPending`이 계속 이어져 관찰 대기가 timeout됐습니다. 5074 NEXT는 보내지 않았고 retry는 0회였습니다. 5001 출력이 명확하고 `OutcomeUnknown=false`였으므로 승인된 비상 TAKE OUT 1회로 STOPALL, 5001 UNLOAD, PGM black과 disconnect를 확인했습니다.
|
||||
|
||||
Round G의 immutable evidence SHA-256은 계획 `E8A6B05E28130665A73CC882A70CD85F023EBF6C59795EC3A56671BE06B06B9A`, 회차 결과 `9B573EBB0F5465164298CA96099E1853DE6E6C00B3D375FB81FC954BED3464A0`, manifest `A0AA8E95CB7F0BE52E21438094D1FFCDA53245C9E33CDC5A659D513EEF19D1EC`입니다.
|
||||
|
||||
수정된 refresh는 periodic tick backlog를 따라잡지 않습니다. 직전 `OnScenePlayed` callback을 lifecycle queue에서 drain한 뒤 full one-shot cooldown을 새로 시작합니다. 5001의 initial cooldown은 2초이고 성공한 refresh 뒤 recurring cooldown은 3초입니다. 따라서 실제 dispatch cadence는 callback/drain 시간과 cooldown의 합으로 원본보다 의도적으로 길지만, recurring refresh 자체는 유지되며 동시에 하나만 실행됩니다. operator NEXT는 refresh epoch를 먼저 stop하고 callback pending이면 DB 대기나 scene query 전에 `PLAY_CALLBACK_PENDING`으로 즉시 반환합니다. 이 요청을 자동 반복하지 않으며 command gate가 바로 풀리므로 TAKE OUT을 사용할 수 있습니다. callback이 완료된 cooldown 구간에서는 NEXT가 정상 실행됩니다. cancellation generation과 refresh status를 한 lock에서 원자적으로 교체·중지·갱신·완료하므로 Stop 뒤 늦은 delay/status write나 이전 세대의 success/fault/finally가 현재 상태를 덮어쓸 수 없습니다.
|
||||
|
||||
Round H `MBNWEB-20260711-H`는 source `fa0eae7b61f57f134dfd30ebf1e59e9cc2cccfc5`(`fa0eae7`), 계획 SHA-256 `55C7755C2F874B4B012239117D4AB717BBCE194E7DCC8DA9B0E40D094FF8CA19`, 회차 결과 SHA-256 `AB70E61C86909F16FE407AAEEF0A5E668F8A4614375448E860C7BE47D687FA0D`, 증적 manifest SHA-256 `CD4EFD0CF64D9C905D7ABF732296E5A80DD4DE362DC7C88FD0D6967846955494`, 서명 유효한 Release x64 MSIX SHA-256 `D51E8CB637860D9F0377AEE6FF691D7D954BA0FF7E30B1AB65443DA153BC5429`에 고정했습니다. 실제 PGM에서 5001 삼성전자, 5074 page 1, 5074 page 2를 순서대로 확인하고 TAKE OUT 뒤 black을 확인했습니다. `OutcomeUnknown=false`, retry 0이었습니다.
|
||||
|
||||
Network Monitoring 최종 증분은 HELLO 1/1, 5001/5074 LOAD 각각 1/1, 5001 PREPARE 3/3, 5074 PREPARE 2/2, PLAY 4/4와 `OnScenePlayed` callback 4회, STOPALL 1/1, 5001/5074 UNLOAD 각각 1/1, FAILURE/ERROR 0/0이었습니다. BYE는 request 1과 별도 success marker 0이었지만 계획의 허용 범위 0~1 안이고, callback drain 뒤 앱 disconnected 상태와 최종 PGM black을 함께 확인해 정상 종료로 판정했습니다.
|
||||
|
||||
사전 검증은 Core 790, Infrastructure 65, Playout 374개 테스트를 Debug/Release x64에서 각각 모두 통과했고(각 구성 합계 1,229), 실제 Oracle/MariaDB read-only query 55건, Visual Studio 2026 Debug/Release x64와 package build, MSIX 서명·설치·package context 감사를 통과했습니다. 같은 패키지의 DryRun에서도 `5001 PREPARE → TAKE IN → 자동 refresh 정확히 1회 → 5074 page 1 → page 2 → TAKE OUT`과 최종 IDLE, DB 2/2 정상, KTAP 미호출을 확인했습니다.
|
||||
|
||||
Round H cleanup은 승인된 TAKE OUT 1회와 두 scene unload, disconnect, 앱·진단 listener 종료, 회차 전용 Live 설정과 승인 환경 제거, PGM/Network Monitoring 창 상태 복원으로 끝났습니다. 정상 회차라 추정 rollback은 실행하지 않았습니다. 장애 rollback은 기본 `DryRun`/`Disabled`로 복귀하거나 조직 절차로 직전 승인 패키지를 복원하는 범위이며, vendor DLL·COM 등록·라이선스·실제 자산은 수정하거나 저장소에 넣지 않습니다. 실제 Live PGM 검증 범위는 허용된 5001/5074뿐이고, 35개 scene 전체 완료 근거는 자동 테스트·55-query 실데이터 smoke·매트릭스입니다.
|
||||
|
||||
패키지 스모크에서는 벤더 x64 COM이 장비에 정식 등록되어 있어야 합니다. MSIX에 벤더 DLL을 복사해 활성화 오류를 우회하지 않습니다. 패키지 컨텍스트에서 COM 활성화가 막히면 `DryRun` 또는 `Disabled`를 유지하고 HRESULT와 등록 검사 결과만 보고합니다.
|
||||
|
||||
## 장애 및 롤백
|
||||
|
||||
Reference in New Issue
Block a user