fix: add truthful KTAP monitoring diagnostics

This commit is contained in:
2026-07-10 12:17:42 +09:00
parent fc932b27f6
commit 306d3a70a1
15 changed files with 764 additions and 33 deletions

View File

@@ -6,6 +6,8 @@
원본 연결은 UI STA에서 `KTAPConnect(1, "127.0.0.1", 30001, 0, event)`를 호출한 뒤 `GetScenePlayer()`를 얻습니다. 연결 성공 판정은 재연결 코드와 동일하게 반환값 `1`입니다.
여기의 `30001`은 원본 시스템의 당시 값일 뿐 새 Test endpoint의 기본값이나 검증값이 아닙니다. 새 설정은 격리 Test Tornado의 현재 `Tools > Option > Control > Network Server > TCP Port`를 직접 확인해 사용합니다. 반환값 `1`도 매뉴얼의 `OnHello` 또는 Network Monitoring `[R]`/`[S]` 확인을 대신하지 않습니다.
새 장면 PREPARE의 기준 순서는 다음과 같습니다.
1. `LoadScene(Cuts\<file>.t2s, <scene alias>)`

View File

@@ -108,6 +108,14 @@ MBN_STOCK_PLAYOUT_RECONNECT_ENABLED
`testSceneAllowlist``trustedLiveOutputEnabled`는 환경 변수로 변경할 수 없으며 로컬 설정 파일에서만 관리합니다. `SceneDirectory`는 Test/Live에서 존재하는 비-reparse 외부 디렉터리여야 하며, 엔진은 상대 `.t2s` 파일을 정규화해 이 루트 밖으로 나가는 경로를 거부합니다. scene file의 basename과 scene name 및 Test allowlist 항목도 서로 일치해야 합니다. 설정 파일은 실행 계정만 읽을 수 있도록 ACL을 제한합니다. 라이선스 키나 인증정보를 이 파일에 기록하지 않습니다.
### KTAP 포트와 Network Monitoring 판정
K3DAsyncEngine 매뉴얼의 `KTAPConnect(bTCP, HostAddress, nHostPort, nClientPort, handler)`에서 Test/Live는 `tcpMode: 1`(TCP)만 허용하므로 로컬 JSON의 `port`는 격리 Test Tornado의 `Tools > Option > Control > Network Server > TCP Port`와 정확히 같아야 합니다. `clientPort`는 UDP일 때만 의미가 있고 `TAP TCP Port`/`TAP UDP Port`는 이 연결의 host port가 아닙니다. 매뉴얼 18쪽의 설명과 26쪽 및 192쪽 예시에 표시된 포트 숫자가 서로 다르므로 `30001`/`30002`를 추정하거나 원본·예제 값을 복사하지 않습니다. 해당 회차 Test 인스턴스 화면의 설정값이 유일한 기준입니다. `playout.example.json``30001`도 DryRun 구조 예시일 뿐 새 Test endpoint의 검증값이 아닙니다.
Tornado2의 `View > Network Monitoring Window`에서 `[R]`은 서버가 클라이언트 요청을 받은 기록, `[S]`는 서버가 응답을 보낸 기록이며 `TCPSession`은 TCP 세션 수입니다(매뉴얼 26~27쪽). 프로세스 감지, COM 등록 probe 또는 COM 객체 생성만으로는 이 기록이 생기지 않습니다. 기본 앱과 `--dry-run`, `--probe`, `--test-plan`은 KTAP를 호출하지 않으므로 빈 모니터가 정상입니다.
상태의 `accepted-unconfirmed``KTAPConnect`가 SDK 성공값 `1`을 반환했다는 뜻일 뿐입니다. 매뉴얼 41쪽의 `OnHello` 콜백이나 실제 `[R]`/`[S]`를 자동 확인했다는 뜻이 아닙니다. 현재 late-bound 어댑터는 282개 메서드 `IKAEventHandler` ABI를 안전하게 패키징하는 검증된 전략이 없어 `ktapHelloObserved``null`로 보고합니다. `lastKtapConnectState`는 현재 연결 상태가 아니라 가장 최근 KTAP dispatch 시도의 증거이며, 화면은 `Connected`/`Faulted` 같은 현재 상태와 분리해 표시합니다. 따라서 격리 `--test-connect`가 성공했는데도 같은 시각의 `[R]`/`[S]`가 전혀 없다면 `--test-sequence`로 진행하지 말고 mode/config 파일, 실제 Network Server TCP Port와 안전 게이트 거부 여부를 먼저 확인합니다.
## 모드와 안전 게이트
`Disabled`는 모든 송출 명령을 거부하는 운영 롤백 모드입니다. `DryRun`은 COM 없이 WebView 동작을 성공 결과로 모의합니다. `Test``Live`만 등록된 COM을 사용할 수 있습니다.
@@ -173,6 +181,8 @@ dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
별도 Test Tornado만 정확히 하나 실행되고 PGM/PROGRAM 창이 전혀 없는 것을 사람이 다시 확인한 뒤 연결만 검증합니다. 이 명령은 씬이나 출력 상태를 변경하지 않고 `Connect → Disconnect`만 요청합니다.
명령 전에 Network Monitoring을 열고 `TCPSession`과 로그 시각을 기준선으로 기록합니다. `--test-plan`에는 변화가 없어야 합니다. `--test-connect`는 짧게 `Connect → Disconnect`하므로 세션 수가 곧 원래 값으로 돌아갈 수 있습니다. 일시적인 세션 수만 보지 말고 같은 시각의 `[R]`/`[S]` 양방향 기록을 확인합니다. `[R]`만 있고 `[S]`가 없거나 양쪽 모두 없으면 명령을 반복하지 말고 중단합니다. JSON의 `completed: true`, `outcomeUnknown: false`, `lastKtapConnectState: "accepted-unconfirmed"`와 운영자가 본 모니터 기록을 함께 확인한 뒤에만 5001→5006 시퀀스로 진행합니다.
```powershell
dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
-c Debug -p:Platform=x64 -- `
@@ -196,7 +206,9 @@ dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
시퀀스는 `Connect → Prepare(5001) → TakeIn → 관찰 → Next(5006) → 관찰 → TakeOut(All) → Disconnect` 순서입니다. 자동 재연결은 CLI가 강제로 비활성화합니다. 성공한 `TakeIn` 뒤 관찰 취소처럼 결과가 확정된 중단이면 `TakeOut(All)`을 한 번만 정리 단계로 요청한 뒤, 정리가 성공한 경우에만 `Disconnect`합니다. 이미 실행 결과가 불명확하거나 `TakeOut`이 어떤 비성공 결과라도 반환하면 출력이 남아 있을 수 있으므로 추가 출력 명령과 SDK `Disconnect`를 보내지 않습니다. 이때 `QuarantineAsync`가 같은 STA에서 제어 메서드 호출 없이 로컬 COM 참조만 해제한 다음 bounded 어댑터 폐기를 수행합니다. quarantine 자체를 완료하지 못하면 의도하지 않은 Disconnect보다 로컬 누수를 택해 일반 Dispose도 생략합니다. 어느 경우든 격리 모니터에서 최종 Test 출력 상태를 사람이 확인해야 합니다.
JSON 결과는 단계별 operation/result code와 `connectRequestIssued`, nullable `comActivationAttempted`, `outputMayBeActive`, quarantine 시도·완료 여부를 제공합니다. `comActivationAttempted``false`는 시도하지 않았음, `true`는 시도했음, `null`은 COM 활성화 시도 여부를 확정할 수 없음을 뜻합니다. `outputMayBeActive: true`이면 자동 정리를 성공으로 확인하지 못했으므로 사람이 격리 출력을 확인해야 합니다. 특히 `Unavailable`, 취소, timeout은 연결 전 거부와 연결 도중 안전 게이트 변화가 같은 결과 code가 될 수 있으므로 추측하지 않`null`로 보고합니다. 로컬 경로, 씬 code, PID, 창 제목, HRESULT 및 엔진 원문 오류는 출력하지 않습니다. `--test-plan``runtimeProcessGateChecked: false`는 자산 계획만 검증했다는 뜻이며 실제 연결 가능성을 증명하지 않습니다.
JSON 결과는 단계별 operation/result code와 `connectRequestIssued`, nullable `comActivationAttempted`, `lastKtapConnectState`, `ktapConnectAttempted`, nullable `ktapConnectAccepted`, nullable `ktapHelloObserved`, nullable `networkMonitoringRecordExpected`, `networkMonitoringCheckRequired`, nullable `networkMonitoringVerified`, `outputMayBeActive`, quarantine 시도·완료 여부를 제공합니다. `connectRequestIssued`는 엔진 API 요청일 뿐 KTAP 통신 증거가 아니며, `comActivationAttempted`도 COM 활성화 추정값일 뿐입니다. `lastKtapConnectState``not-attempted`, `attempted`, `accepted-unconfirmed`, `failed` 중 하나입니다. `networkMonitoringRecordExpected`는 성공값을 받은 경우 `true`, dispatch가 없으면 `false`, local reflection/COM 실패 또는 timeout으로 서버 도달을 예측할 수 없으면 `null`입니다. `networkMonitoringCheckRequired`는 KTAP dispatch 경로에 들어간 모든 경우 `true`이며, `networkMonitoringVerified`는 앱이 Tornado2 UI를 판독하지 않으므로 항상 `null`입니다. 운영자가 직접 `[R]`/`[S]`를 확인해야 합니다. `outputMayBeActive: true`이면 자동 정리를 성공으로 확인하지 못했으므로 사람이 격리 출력을 확인해야 합니다. 특히 `Unavailable`, 취소, timeout은 연결 전 거부와 연결 도중 안전 게이트 변화가 같은 결과 code가 될 수 있으므로 추측하지 않니다. 로컬 경로, 씬 code, PID, 창 제목, HRESULT 및 엔진 원문 오류는 출력하지 않습니다. `--test-plan``runtimeProcessGateChecked: false`는 자산 계획만 검증했다는 뜻이며 실제 연결 가능성을 증명하지 않습니다.
연결 timeout은 COM 활성화와 KTAP dispatch 사이의 원자적 게이트를 닫습니다. timeout이 먼저 게이트를 닫으면 늦게 끝난 STA 작업도 `KTAPConnect`에 진입할 수 없고 `lastKtapConnectState: "not-attempted"`로 남습니다. dispatch가 먼저 게이트를 획득한 경우에는 `attempted` 이상으로 보고하고 `networkMonitoringCheckRequired: true`로 남겨 운영자 확인을 요구합니다.
현재 장비처럼 PGM Tornado가 실행 중이거나 loopback 포트를 PGM이 소유한 상태에서는 `--test-connect``--test-sequence`를 실행하지 않습니다. 기존 Test 엔진도 exactly-one Tornado2, non-PGM 제목 정규식, loopback literal, Test outputChannel, 외부 non-reparse scene root와 allowlist를 연결 전 및 각 명령 전에 재검사합니다.