# 개발 PGM 인수 PC 실제 송출 확인 절차

## 적용 범위

이 절차는 상사 또는 인수 담당자의 PC가 **방송에 연결되지 않은 지정 개발 장비**이고, 그
장비의 로컬 Tornado2 `PGM`이 개발 검증 대상임을 확인한 경우에만 사용한다. 창 제목이 `PGM`인
것만으로 개발 장비임이 증명되지는 않는다. 실제 방송 PROGRAM일 가능성이 있거나 라우팅을
확인할 수 없으면 시작하지 말고 [운영·비지정 환경 승인 게이트](PLAYOUT_OPERATIONS.md#운영비지정-환경-승인-게이트)를
적용한다.

이 절차가 여는 Live 경로는 지정 개발 PC의 `Debug|x64`와 `Release|x64`
`MBN_STOCK_WEBVIEW.LegacyParityApp - Development Live (Package)`에 유효하다.
사용자·시스템 환경 변수에 Live 승인을 영구 저장하지 않는다.

## Git 밖에서 확인하거나 준비할 항목

상사 PC에 이미 `Cuts`, `Res\MmoneyCoder.ini`, Tornado2/K3D x64와 장비 라이선스가 있다면
같은 항목을 다시 전달하지 않는다. 대신 기존 설치 위치가 이번 인수 대상이 맞는지 확인하고,
다음 항목을 확인한다.

- DB endpoint와 계정 정보. 메신저 화면, 작업 기록 또는 Git에 값을 남기지 않는다.
- 기존 코더가 실제 실행에 사용하던 서로 이웃한 `Cuts`와 `Res` 폴더.
- Tornado2/K3D x64 설치본과 해당 장비용 라이선스 상태.
- 개발 PGM의 로컬 Network Server가 회사 기본값 `127.0.0.1:30001`을 사용한다는 사실과
  출력 라우팅.

해당 PC에 승인된 `Cuts`/`Res`가 없을 때만 `New-LegacyRuntimeBundle.ps1`로 생성한 runtime
bundle ZIP과 별도 신뢰 경로로 전달할 기대 SHA-256을 추가로 준비한다.

첫 실행 설정은 예상 HKLM Registry64 등록, CLSID·ProgID·TypeLib, AMD64, vendor 폴더 배치와
HKCU override 부재를 먼저 검증한다. 모두 맞을 때만 현재 설치된 native/Interop 두 DLL의
SHA-256을 이 PC의 최초 기준으로 자동 고정한다. 이후 DLL이나 등록이 바뀌면 자동 재승인하지
않고 Development Live를 차단한다. 이 지속 기준은 사용자 전용
`%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\k3d-pins.local.json`에 저장하며 Git에는 넣지
않는다. 라이선스 파일, DLL, 인증서 또는 자산을 앱 폴더에 임의 복사해 등록·라이선스 검사를
우회하지 않는다.

## 1. 개발 장비와 대상 고정

담당자 두 사람이 다음 내용을 먼저 확인한다.

1. 이 PC와 로컬 Tornado2/PGM은 개발용이며 실제 방송 라우팅에 영향이 없다.
2. `Tornado2*` 프로세스는 정확히 하나이고 주 창 제목은 승인값과 정확히 일치한다.
3. Tornado2의 `Tools > Option > Control > Network Server > TCP Port`가 지정 개발 환경의
   회사 기본값 `30001`인지 확인한다. 다른 값이면 자동 첫 실행 설정을 사용하지 않는다.
4. 해당 TCP LISTEN 소유 PID와 Tornado2 PID가 같고, 실행 도중 프로세스 세대가 바뀌지 않는다.
5. `View > Network Monitoring Window`와 PGM 화면을 동시에 관찰할 담당자가 있다.

한 항목이라도 불명확하면 이후 명령을 보내지 않는다.

## 2. 기존 자산 보유 PC: clone 후 1회 초기화

상사 PC처럼 승인된 자산과 벤더 설치가 이미 있는 경우에는 이 흐름을 우선 사용한다. 별도
PowerShell 명령은 필요 없다.

1. 저장소를 clone하고 `MBN_STOCK_WEBVIEW.sln`을 Visual Studio 2026에서 연다.
2. `Debug|x64`, `Legacy Parity App (VS F5)`,
   `MBN_STOCK_WEBVIEW.LegacyParityApp - Development Live (Package)`를 선택한다.
3. 첫 번째 F5로 소스 전용 첫 실행 설정 앱을 연다. 이 프로세스는 DB와 송출 엔진을
   만들지 않고 Tornado2/PGM에 연결하지 않는다.
4. `Cuts 폴더 선택`에서 실제 실행 자산의 `Cuts` 폴더를 선택한다.
5. `Res 폴더 선택`에서 기존 코더가 사용하는 실제 `Res` 폴더를 선택한다.
6. 두 폴더가 같은 공통 부모 아래의 정확한 `Cuts`, `Res`인지 확인하고 `설정 시작`을 누른다.
7. `설정 완료`가 표시되면 창을 닫고 F5를 한 번 더 누른다.

소스 트리의 오래된 `RES`나 이름이 비슷한 백업 폴더를 선택하지 않는다. `설정 시작`은
두 폴더의 고정 로컬 경로만 다음 위치에 저장한다.

- `%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\runtime-folders.local.json`
- 저장소의 Git 제외 `Directory.Build.local.props`

이 버튼은 폴더 안의 파일을 열거·파싱·복사하지 않으며 PowerShell, `dotnet build`, DB 복사,
K3D 검사, Live 승인 발급 또는 Tornado2/PGM 명령을 실행하지 않는다. 따라서 경로 저장은
즉시 완료되어야 한다. `Cuts`와 `Res`의 실제 파일 검사는 다음 F5의 빌드 또는 해당 기능을
사용하는 시점에 필요한 파일 단위로 수행된다.

전체 Debug x64 빌드는 설정 창을 닫고 누르는 다음 F5에서 진행된다. 필요하면 같은 조건을
별도 MSBuild 인자나 환경 변수 없이 다음 명령으로 확인할 수 있다.

```powershell
dotnet build .\src\MBN_STOCK_WEBVIEW.LegacyParityApp\MBN_STOCK_WEBVIEW.LegacyParityApp.csproj `
  -c Debug `
  -p:Platform=x64
```

출력에 외부 runtime 경로가 활성화되었다는 메시지가 있어야 한다. 소스 전용 모드가 계속
표시되면 Visual Studio에서 다시 빌드한다. Live 기동이 차단되면 별도의 Development Live
승인이나 보호 설정이 아직 유효하지 않은 것이다.
같은 clone에서는 이후 `git pull` 뒤 Visual Studio 2026에서 `Debug|x64`, 시작 대상
`Legacy Parity App (VS F5)`, 실행 프로필
`MBN_STOCK_WEBVIEW.LegacyParityApp - Development Live (Package)`를 선택해 F5로 시작할 수
있다. 저장소를 새 폴더에 다시 clone하면 첫 실행 경로 저장을 다시 진행한다. DB overlay,
K3D pin과 Development Live 승인이 없는 새 PC에서는 아래 수동 초기화 절차를 별도로
완료하기 전까지 전체 앱 기동을 차단한다. K3D DLL 변경은 경로 저장을 반복해도 자동
승인되지 않는다. 최초 실제 동작
확인은 아래 최소 인수 시퀀스의 `5001` 하나로 제한한다.

### Development Live까지 준비할 때

첫 실행 경로 저장과 별개로 DB overlay, K3D pin과 Development Live 승인까지 새로
준비해야 할 때 저장소 루트에서 다음 수동 명령을 사용한다. 이 명령은 전체 Debug 빌드
검증까지 수행하므로 단순 폴더 저장 버튼보다 오래 걸리는 것이 정상이다.

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Initialize-ExistingDevelopmentPc.ps1 `
  -LegacyRuntimeSourceRoot '<Cuts와 Res의 공통 부모>' `
  -NoFolderPicker `
  -ConfigureDevelopmentLive `
  -PlayoutHost 127.0.0.1 `
  -PlayoutPort 30001 `
  -PinRegisteredK3D
```

기존 로컬 runtime, DB 또는 Live 설정과 다르면 자동으로 덮어쓰지 않는다. 변경 대상을 검토한
뒤에만 `-ReplaceRuntimeBinding`, `-ReplaceDatabaseProfile`, `-ReplaceLiveConfig` 중 필요한
항목을 명시한다. 수동 모드는 기존처럼 독립 승인된 `-NativeSha256`과 `-InteropSha256`을
사용할 수도 있으며, 이 두 값과 `-PinRegisteredK3D`는 함께 쓸 수 없다. 이 스크립트는
첫 실행 화면에서 자동으로 호출되지 않는다.

## 3. 자산이 없는 PC 대안: 검증된 Git 밖 runtime bundle 설치

기존 자산 보유 PC에서 2단계 초기화가 성공했다면 이 단계는 건너뛴다. 이 단계는 승인된
`Cuts`/`Res`가 없는 새 개발 PC에만 사용하는 대안이다.

원본 runtime tree를 새 PC에 직접 복사하거나 수동으로 ZIP을 만들지 않는다. 원본을 보유한
지정 개발 장비에서 읽기 전용 `bin\Debug`을 입력으로 다음 스크립트를 실행한다.

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\New-LegacyRuntimeBundle.ps1 `
  -LegacyRuntimeSourceRoot '<read-only-MBN_STOCK_N-bin-Debug>' `
  -OutputDirectory '<new-empty-bundle-output-directory>'
```

`-OutputDirectory`를 생략하면 Git 제외
`artifacts\legacy-runtime-bundles\<UTC>-<GUID>` 아래에 새 출력 디렉터리를 만든다. 결과물은
다음 세 파일이다.

```text
LegacyRuntimeBundle.zip
LegacyRuntimeBundle.manifest.json
LegacyRuntimeBundle.zip.sha256
```

생성기는 전체 `Cuts` tree와 프로젝트가 허용한 비민감 `Res` 파일 34개만 폐쇄형으로 묶는다.
`MmoneyCoder.ini`와 그 복사본·백업, DB 파일, 자격증명, vendor DLL, 라이선스, 인증서,
실행 파일과 임의 archive는 거부한다. 따라서 `MmoneyCoder.ini`는 Debug를 포함한 어떤 빌드
입력·출력이나 runtime bundle에도 필요하지 않으며 넣어서는 안 된다.

ZIP은 승인된 사내 전달 경로로 보내고, `LegacyRuntimeBundle.zip`의 기대 SHA-256은 ZIP 또는
동봉 `.sha256` 파일과 **다른 신뢰 경로**로 인수자에게 전달한다. 같은 폴더의 해시 파일만 보고
ZIP을 신뢰하지 않는다.

새 PC의 저장소 루트에서 ZIP을 직접 풀지 말고 다음 초기화 스크립트를 사용한다.

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Initialize-LegacyRuntimeBundle.ps1 `
  -ZipPath '<received-LegacyRuntimeBundle.zip>' `
  -ExpectedSha256 '<separately-approved-64-hex-zip-sha256>'
```

저장소 루트가 현재 디렉터리가 아니면 검토한 절대 경로를 `-RepositoryRoot`로 추가한다.
초기화기는 압축을 풀기 전에 별도로 전달받은 ZIP SHA-256을 확인하고, manifest와 각 파일의
경로·길이·SHA-256, reparse/root 이탈과 금지 파일 부재를 검사한다. 성공한 bundle은 기본적으로
다음 Git 밖 경로에 설치한다.

```text
%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\RuntimeBundles\<ZIP-SHA256>
```

그 뒤 저장소 루트의 Git 제외 `Directory.Build.local.props`를 만들어
`LegacyRuntimeAssetsMode=Required`와 검증된 설치 root를 고정한다. 이 파일을 손으로 만들거나
경로를 환경 변수로 임시 주입하지 않는다. ZIP, 설치 root와 `Directory.Build.local.props`도
Git에 추가하지 않는다.

초기화기가 출력한 설치 root의 `Cuts`를 대상으로 coverage를 확인한다.

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Test-LegacyCutCoverage.ps1 `
  -CutRoot '<initialized-runtime-root>\Cuts'
```

현재 authoritative 자산에도 다음 영상 14개는 없다.

- `s5006`: `Video\큐브배경.vrv` 1개
- `s6001`: `Video\20201008_<국가>.vrv` 13개

coverage가 이 14개를 누락으로 보고하는 동안 관련 action은 PREPARE하지 않는다. 다른 scene,
built-in asset, 빈 파일, root 이탈 또는 reparse 항목이 하나라도 발견되면 인수를 중단한다.
이 스크립트는 자산이 하나라도 없으면 의도적으로 실패 종료하므로, 결과가 정확히 알려진 14개
영상 누락뿐인 경우에도 전체 coverage `Passed`로 기록하지 않고 영향 없는 scene만 제한적으로
인수한다. 누락 영상을 비슷한 파일로 대체하지 않는다.

초기화 뒤에는 별도 MSBuild 경로 인자나 환경 변수 없이 다음 빌드가 성공하는지 확인한다.

```powershell
dotnet build .\src\MBN_STOCK_WEBVIEW.LegacyParityApp\MBN_STOCK_WEBVIEW.LegacyParityApp.csproj `
  -c Debug `
  -p:Platform=x64
```

앱이 소스 전용 모드라고 표시되거나 `bin\SourceOnly`에서 시작되면 Development Live를 진행하지
않는다. bundle 초기화 결과와 `Directory.Build.local.props`를 고친 뒤 전체 자산 빌드부터 다시
확인한다.

## 4. DB 로컬 설정 확인 또는 대안

2단계의 기존 PC 초기화는 검증한 `MmoneyCoder.ini`를 다음 실행 사용자 전용 경로에 이미
복사한다.

```text
%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Res\MmoneyCoder.ini
```

파일 내용의 원본 일치 여부와 현재 Windows 사용자 전용 ACL을 확인하되 값을 화면 캡처나 로그에
남기지 않는다. 기존 파일이 원본과 다르면 초기화기는 자동으로 덮어쓰지 않는다. 대상이 정확한지
확인한 뒤 2단계 명령에 `-ReplaceDatabaseProfile`을 추가한다. 이 INI는 빌드 입력·출력이나
runtime bundle에 포함되지 않는다.

3단계의 외부 bundle은 DB 파일을 의도적으로 포함하지 않으므로 그 흐름에서는 다음 JSON
초기화가 필요하다. 기존 INI를 사용하지 않고 새 JSON 설정으로 전환하기로 명시적으로 결정한
경우에는 **아래 INI overlay가 존재하지 않는 것을 먼저 확인한 뒤에만** 2단계 초기화에
`-SkipDatabaseProfile`을 주고 같은 대안을 사용한다. 이 옵션은 기존 INI를 삭제하거나
비활성화하지 않으며, INI가 남아 있으면 앱이 JSON보다 먼저 사용한다. 기존 overlay가 있는
PC의 전환은 이 절차에서 임의 삭제하지 말고 별도 검토된 자격증명 제거·전환 작업으로 처리한다.
JSON 경로는 다음과 같다.

```text
%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\database.local.json
```

저장소 루트에서 초기화 스크립트를 사용한다. Oracle이 service name을 쓰는 환경이면
`-OracleSid` 대신 `-OracleServiceName`을 사용한다.

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Initialize-DatabaseConfig.ps1 `
  -OracleHost '<approved-host>' `
  -OraclePort <approved-port> `
  -OracleSid '<approved-sid>' `
  -OracleUserName '<approved-user>' `
  -MariaDbHost '<approved-host>' `
  -MariaDbPort <approved-port> `
  -MariaDbDatabase '<approved-database>' `
  -MariaDbUserName '<approved-user>'
```

비밀번호는 스크립트의 보안 프롬프트에만 입력한다. 생성 파일은 현재 Windows 사용자만 읽고
수정할 수 있어야 한다. 개발 DB가 아니라 운영 DB를 가리키거나 endpoint가 불명확하면 송출
검증으로 넘어가지 않는다. DB 연결 확인은 [DB 운영 가이드](DATABASE.md)의 read-only smoke만
먼저 수행하고, 실패 시 Tornado 명령을 보내지 않는다.

## 5. K3D 설치, 라이선스와 기준 해시 확인

벤더 절차로 Tornado2/K3D x64와 장비 라이선스를 먼저 설치한다. 저장소의 점검은 레지스트리와
파일을 읽을 뿐 COM을 활성화하지 않는다. 2단계 초기화는 이 검사를 항상 수행하고 `Valid`,
`ComActivated=false`가 아니면 로컬 설정을 완료하지 않는다. 다음 명령은 동일한 검사를 별도로
다시 확인할 때 사용한다.

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Inspect-K3DRegistration.ps1
```

Registry64, TypeLib/CLSID 양방향 매핑, `Apartment`, AMD64 PE, HKCU override 부재 검사가 모두
성공해야 한다. 점검 성공은 라이선스 성공을 대신하지 않으므로 벤더 방식으로 라이선스도 별도
확인한다. 첫 실행 설정은 이 검사를 통과한 native와 Interop 파일의 SHA-256을 최초 기준으로
고정하며, 이후 실제 파일이 기준값과 하나라도 다르면 중단한다. 수동 승인 모드에서는 두 파일이
각각 독립 승인된 SHA-256과 일치해야 한다.

지속 pin 파일의 경로는 다음과 같다.

```text
%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\k3d-pins.local.json
```

이 파일은 정확한 JSON 계약과 현재 Windows 사용자 전용 ACL로 원자적으로 생성된다. 최초
기준이 고정된 뒤에는 나머지 설정의 성공 여부와 무관하게 파일을 삭제하거나 편집해 새 DLL을
승인하지 않는다.

### K3D DLL이 정식으로 교체된 경우

벤더 업데이트 등으로 DLL이 의도적으로 바뀌었다면 두 파일을 별도 배포 증적이나 관리자 검수로
독립 확인한 뒤에만 수동 fallback을 사용한다. 현재 설치 파일에서 계산한 값만 보고 같은
값을 승인하지 않는다. 일반적인 교체 명령은 다음과 같으며
`-ReplaceK3DPin`은 `-PinRegisteredK3D`와 함께 사용할 수 없다.

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Initialize-ExistingDevelopmentPc.ps1 `
  -LegacyRuntimeSourceRoot '<Cuts와 Res의 공통 부모>' `
  -NoFolderPicker `
  -ConfigureDevelopmentLive `
  -PlayoutHost 127.0.0.1 `
  -PlayoutPort 30001 `
  -NativeSha256 '<independently-verified-64-hex-native-sha256>' `
  -InteropSha256 '<independently-verified-64-hex-interop-sha256>' `
  -ReplaceK3DPin `
  -ReplaceLiveConfig
```

runtime이나 DB 위치도 의도적으로 달라졌을 때만 각각 `-ReplaceRuntimeBinding`,
`-ReplaceDatabaseProfile`을 추가한다. 해시가 실제 등록 파일과 다르거나 K3D 등록 검사가
실패하면 기존 pin을 보존하고 중단한다.

## 6. 보호된 로컬 송출 설정

별도 수동 Development Live 초기화는 지속 K3D pin을 확인한 뒤 아래 송출 설정 두 파일도
마지막 기능 설정 단계에서 검증 후 새로 발급한다. 기존 승인은 매번 먼저 무효화하며 runtime·DB·Debug 빌드가 모두
성공하지 않으면 새 Live 승인 파일을 남기지 않는다. 자산 없는 PC의 3단계 bundle 흐름처럼
설정만 별도로 초기화해야 할 때는 저장소 루트에서 다음 스크립트를 실행한다. 이 수동 경로의
두 해시는 별도로 확인한 값이어야 한다. 지정 개발 PC의 endpoint는
`127.0.0.1:30001`로 고정한다. 기존 승인 프로필이 별도 출력 채널을 사용할 때만 검증된 숫자를
`-OutputChannel`로 추가하며, 기본 player를 쓰는 경우에는 생략한다.

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
  -File .\scripts\Initialize-DevelopmentLiveConfig.ps1 `
  -PlayoutHost 127.0.0.1 `
  -PlayoutPort 30001 `
  -NativeSha256 '<independently-approved-64-hex-native-sha256>' `
  -InteropSha256 '<independently-approved-64-hex-interop-sha256>'
```

스크립트는 `%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config` 아래의 일반 파일 두 개를 원자적으로
생성하고 현재 Windows 사용자 전용 ACL을 적용한다. LocalAppData 상위 경로에 reparse point가
있거나 기존 파일이 있으면 중단한다. 기존 파일을 덮어쓸 때는 내용을 별도로 검토하고 대상이
정확한 경우에만 `-Force`를 명시한다. `-Force` 갱신은 기존 Live 승인 파일을 먼저 무효화하므로
두 파일 중 하나라도 쓰기에 실패하면 송출 승인이 남지 않는다. 경로·endpoint·해시를 Git이나
실행 로그에 복사하지 않는다.

### `playout.local.json`

초기화 스크립트가 만든 파일을 읽기 전용으로 검토해 다음 계약과 일치하는지 확인한다.
[`Config/playout.example.json`](../Config/playout.example.json)은 비밀값 없는 구조
참고용일 뿐 수동 복사본으로 사용하지 않는다.

| 항목 | 인수 값 |
|---|---|
| `mode` | 항상 `Live`. Debug와 Release가 같은 보호된 프로필을 사용한다. |
| `host` | 로컬 PGM이면 숫자형 loopback `127.0.0.1`. `localhost` 또는 원격 주소를 추정하지 않는다. |
| `port` | 지정 개발 환경의 고정 Network Server TCP port `30001` |
| `tcpMode` / `clientPort` | `1` / `0` |
| `sceneDirectory` | `null`. 검증된 로컬 runtime이 빌드 출력에 배치한 기본 `Cuts`를 사용한다. |
| `outputChannel` | 승인된 개발 PGM 라우팅 값. 기존 승인 프로필이 기본 player를 쓰는 경우에만 `null` |
| `testSceneAllowlist` | 아래 active alias 45개만 허용 |
| `trustedLiveOutputEnabled` | `true` |
| `reconnectEnabled` / `maximumReconnectAttempts` | 인수 회차에서는 `false` / `0` |
| `maximumAutomaticRefreshesPerTakeIn` | 최초 인수 회차에서는 `0` |

```text
5001, 5006, 5011, 5016, 50160, 5023, 5024, 5025, 5026, 5029,
5032, 5037, 5068, 5070, 5072, 5074, 5076, 5077, 5078, 5079,
5080, 5081, 5082, 5083, 5084, 5085, 5086, 50860, 5087, 5088,
6001, 6067, 8001, 8002, 8003, 8018, 8032, 8035, 8040, 8046,
8051, 8056, 8061, 8067, N5001
```

`8010`, `8086`, 임의 파일명과 절대 scene 파일 경로는 allowlist에 추가하지 않는다. 실제 endpoint,
채널, 경로와 allowlist가 든 이 파일을 Git이나 지원 첨부파일에 넣지 않는다.

Development Live로 승인된 프로세스는 이 26개 속성을 strict JSON으로 다시 읽으며, 중복·추가
속성, 대소문자 차이, 잘못된 타입을 거부한다. 상속된 `MBN_STOCK_PLAYOUT_*` 환경 변수와 기존
운영자 scene/resource/background 선택은 적용하지 않는다. endpoint는 숫자형 loopback,
scene root는 실행 파일 옆 검증된 `Cuts`로 마지막에 다시 고정한다. DB도
`%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Res\MmoneyCoder.ini`를 우선하고, 없을 때만 보호된
`Config\database.local.json`을 사용하며 DB 환경 변수는 무시한다. 이 strict 경로가 성립하지
않으면 Live 엔진 기동을 차단하고 명확한 오류를 표시한다.

### `playout.development-live.local.json`

경로는 다음과 같다.

```text
%LOCALAPPDATA%\MBN_STOCK_WEBVIEW\Config\playout.development-live.local.json
```

파일에는 정확히 다음 다섯 속성만 둔다.

```json
{
  "schemaVersion": 1,
  "mode": "Live",
  "authorization": "I_AUTHORIZE_LIVE_PROGRAM_OUTPUT_FOR_THIS_LAUNCH",
  "nativeSha256": "<independently-approved-64-hex-native-sha256>",
  "interopSha256": "<independently-approved-64-hex-interop-sha256>"
}
```

주석, trailing comma, 중복·추가 속성을 넣지 않는다. 수동 승인 모드의 두 해시와 승인 근거는
Git 밖에 보관하고 현재 설치 파일에서 즉석 계산한 값으로 placeholder를 채우지 않는다. 첫 실행
설정은 지속 K3D pin을 먼저 검증한 뒤 그 기준값으로 이 Live 승인 파일을 생성한다. 자세한
strict 파일 규칙은
[Visual Studio Development Live 설정](DEVELOPMENT_LIVE_VISUAL_STUDIO.md)을 따른다.

## 7. 정확한 로컬 PGM 연결 전용 확인

Network Monitoring을 먼저 연다. 독립 승인 해시는 이 진단을 실행할 현재 PowerShell
프로세스에만 설정한 뒤 실제 port로 connect-only 진단을 한 번 실행한다.

```powershell
$env:MBN_STOCK_K3D_NATIVE_SHA256 = '<independently-approved-native-sha256>'
$env:MBN_STOCK_K3D_INTEROP_SHA256 = '<independently-approved-interop-sha256>'

dotnet run --project .\tools\MBN_STOCK_WEBVIEW.PlayoutSmoke `
  -c Debug -p:Platform=x64 -- `
  --pgm-connect-diagnostic `
  --i-understand-this-will-contact-current-pgm-tornado-via-ktap-connect-and-disconnect-only `
  --host 127.0.0.1 `
  --port 30001 `
  --expected-pgm-window-title PGM
```

이 진단은 KTAP `Connect → Disconnect`만 수행하고 render API를 노출하지 않지만 PGM 제어
세션에는 접촉한다. 성공 결과의 `completed: true`, `outcomeUnknown: false`,
`renderCommandSurfaceExposed: false`, `renderCommandAttempted: false`와 같은 시각의 Network
Monitoring `HELLO` 성공을 사람이 함께 확인한다.

timeout, `OutcomeUnknown`, 대상 PID·시작 시각·listener 변경 또는 결과 불일치가 생기면 같은
진단을 반복하지 않는다. 새 명령을 보내지 말고 PGM과 Network Monitoring 상태를 읽기 전용으로
확인한 뒤 새 인수 회차를 계획한다.

## 8. Development Live 최소 인수 시퀀스

1. 기존 앱 인스턴스를 정상 종료한다.
2. Visual Studio에서 구성 `Debug` 또는 `Release`, 플랫폼 `x64`, 시작 대상
   `Legacy Parity App (VS F5)`를 선택한다.
3. 실행 프로필을
   `MBN_STOCK_WEBVIEW.LegacyParityApp - Development Live (Package)`로 선택하고 F5로 시작한다.
4. 앱이 소스 전용이거나 Live 기동 차단 오류를 표시하면 실제 명령을 시도하지 않는다.
   runtime 초기화와 로컬 binding, 시작 인자와 두 로컬 파일을 고친 뒤 앱을 새로 시작한다.
5. 최초 인수는 자산이 완전한 사전 합의 scene 하나만 사용한다. 기본 최소 회차는 active alias
   `5001`의 `CONNECT 1회 → PREPARE 1회 → 화면·Network Monitoring 확인 → TAKE IN 1회
   → 화면 확인 → TAKE OUT 1회 → DISCONNECT 1회`다.
6. PREPARE 성공과 PGM 상태를 확인하기 전에는 TAKE IN을 누르지 않는다. NEXT, Page NEXT,
   timer refresh, 다른 scene은 최초 최소 회차에 추가하지 않는다.
7. TAKE OUT과 DISCONNECT 결과가 명확히 성공한 뒤 앱을 정상 종료한다.

각 단계에서 앱 결과, lifecycle callback, PGM 화면과 Network Monitoring 기록이 서로 맞아야
한다. timeout, `OutcomeUnknown`, callback 누락, 화면 불일치, 대상 identity 변경 또는 license/hash/
allowlist 실패가 발생하면 다음 동작, 같은 동작 반복, 반대 동작이나 추측성 cleanup을 하지 않는다.
PGM/Tornado2를 강제 종료하지 말고 상태를 보존한다.

## 9. Live 종료와 인수 완료 조건

Live 앱을 종료하면 부트스트랩이 만든 Live 환경은 프로세스와 함께 사라져야 한다.
`playout.local.json`의 `mode`는 계속 `Live`여야 한다. 다음 실행도 같은 보호된 Live
부트스트랩을 사용하며, 별도의 비송출 프로필로 전환하지 않는다.

다음 항목이 모두 맞아야 인수를 완료한다.

- 지정 개발 PC와 정확한 로컬 PGM 대상 확인
- 기존 자산 또는 외부 bundle에서 설치한 검증된 로컬 runtime과 허용 scene 확인
- K3D x64 등록, 장비 라이선스, 지속 pin과 자동 고정 또는 수동 승인된 두 기준 해시 확인
- 개발 DB read-only smoke 성공
- 지속 K3D pin과 두 `%LOCALAPPDATA%` 송출 설정 파일의 내용·ACL 검증
- connect-only 진단과 최소 5001 회차가 retry 0, `OutcomeUnknown=false`로 종료
- 최종 TAKE OUT/IDLE, DISCONNECT와 정상 Live 재시작 확인
- 누락 영상 14개 관련 action이 제한 상태임을 인수자에게 고지

실제 endpoint, 자격증명, 해시, 자산 경로, 화면 캡처와 Network Monitoring 증거는 승인된
Git 밖 인수 기록에만 보관한다.

## Git에 넣지 않는 항목

- `Cuts`, `.t2s`, image, texture, `.vrv` 영상과 방송 자산
- `LegacyRuntimeBundle.zip`, manifest·해시 파일, 설치된 `RuntimeBundles`와
  `Directory.Build.local.props`
- `Res\MmoneyCoder.ini`, `database.local.json`과 DB 자격증명
- `playout.local.json`, `playout.development-live.local.json`,
  `runtime-folders.local.json`, `k3d-pins.local.json`
- Tornado/K3D native DLL, Interop DLL, 라이선스 파일·키
- native/Interop 승인 해시와 승인 근거
- MSIX 서명 인증서, 개인 키와 암호
- 실제 host, port, output channel, PGM 정보
- 실제 출력 캡처, Network Monitoring 화면과 민감 로그

Debug Package 빌드가 로컬 실행을 위해 승인 runtime 자산을 stage하더라도 그 출력,
`AppPackages` 또는 설치 파일을 소스 저장소나 일반 첨부파일로 올리지 않는다. 고객 배포본으로
재사용하지도 않는다. Git에는 소스, 비밀값 없는 예제와 이 절차만 유지한다.
