# MBNWEB-20260712-M-R2 기존 종료 대화상자 확인 계획

M-R1은 운영체제 정상 닫기 요청을 정확히 한 번 보낸 뒤, WinUI가 같은 제목을 dialog
Window와 제목 Text로 각각 노출하는 정상 구조를 중복 제목으로 오판해 실패 폐쇄됐다.
이 회차는 닫기 요청을 다시 보내지 않고 **이미 열린 정확한 중립 대화상자의
PrimaryButton만 한 번 확인**하기 위한 별도 confirm-only 회차다. M-R2는 승인 후
정확히 한 번 시작됐지만, 사전 검사에서 기존 앱이 이미 종료된 것을 확인해
`FAIL_KNOWN_NO_COMMAND`로 실패 폐쇄됐다. M-R2가 실행한 UI 확인, DISCONNECT/BYE,
송출 명령은 모두 0이며 재시도하지 않는다.

## 실행 결과와 외부 정상 종료

| 항목 | 값 |
|---|---|
| M-R2 승인 | 2,804 bytes, `2ACF4393E67CF482A14810ED8CAD213866E1567EF180B3E0AC4CCA5895EBFB53` |
| M-R2 결과 | 1,755 bytes, `4BC8F0B230DA0CB00784BD2F408FC6840F5BDC6AEBDA721890CD70AF5E120CED` |
| 상태 | `FAIL_KNOWN_NO_COMMAND`, `outcomeUnknown=false` |
| 실행 / confirm dispatch / complete journal | 모두 생성되지 않음 |
| M-R2 CloseMainWindow / Invoke / DISCONNECT / 송출 | 모두 `0` |
| 기존 앱·CDP | PID 37916 / 34988 모두 종료 |
| 기존 Tornado TCP | 제거됨 |
| Tornado2 | PID 6972와 `0.0.0.0:30001` listener 유지 |
| PGM | 64표본 최대 RGB 0, 144×81 검은 화면 |

M-R2 승인 기록은 `2026-07-13T01:40:15.5163471Z`에 생성됐다. 기존 세션은
`01:40:19.877Z`에 Network Monitoring에 `[R] BYE Bye` 요청 한 줄을 남겼고,
Windows AppModel은 `01:40:20.2324722Z`에 기존 MSIX 컨테이너를 제거했다. M-R2
도우미는 그보다 늦은 `01:40:23.3721293Z`에 시작해 약 0.05초 뒤 앱 부재로
중단됐으므로 BYE와 앱 종료는 M-R2에서 발생하지 않았다.

종료 전 Network 기준은 142,844 chars,
`839882172C79211517E4C3C81EBF95E65B322B6418B086985EE13E917A3F5A37`이고,
종료 뒤에는 142,969 chars,
`5773CD65CFCAA08D0112775AB39CA9E3E034086EAD87F0E0D424E3BF876A38F7`이다.
신규 suffix 125 chars의 SHA-256은
`0316ED8228677624A7C557F506577EC6830B3EE3F1FB41C61761BC4C0F5910E2`이며 BYE 요청
1회만 포함하고 성공·실패·오류·scene·송출 명령은 없다. 코드의 정상 종료 경로와
일치하므로 기존 live 세션은 외부 동작으로 정상 종료된 것으로 기록하되, 사람의
클릭인지 다른 UI 자동화인지는 단정하지 않는다.

M-R2 결과 뒤 `2026-07-13T01:40:24.1318444Z`에 Explorer를 부모로 하는 새 앱
PID 10868과 새 WebView 루트 PID 35328이 시작됐다. 이는 기존 세대와 분리해
취급한다. 새 세대는 MariaDB/Oracle DB 소켓만 가지고 Tornado/30001 연결,
9339 debug listener와 신규 HELLO는 없다. 후속 live 검증은 이 새 세대를 기준으로
다시 계획·승인해야 한다.

위 상태는 별도 읽기 전용 회차 `MBNWEB-20260712-M-R2-AUDIT`로 고정했다.
외부 시스템 조작 예산과 실제 조작은 모두 0이다.

| 감사 산출물 | 크기 | SHA-256 |
|---|---:|---|
| 감사 계획 | 18,716 bytes | `686631F6F8BF518F2B15FC10B46E8F8F9BD6337A42560D035E8E82CDDADE597C` |
| collector | 21,256 bytes | `FB44C78612697A5000432BEB47B6F5EF0FD2F1998B04EBB4D678ABF71C5B5817` |
| 운영/시험 계획 빌더 | 13,916 bytes | `737440149D5B23845770E15C8D0430D3490878222E20B3CA9A32222881CB4713` |
| `external-close-audit.json` | 12,042 bytes | `4466C7131D9D6D2BFBABC1B11D8BA685085EC8D9FE6D2393AE2F69E6A6F90955` |
| 정적 시험 | 6,031 bytes | `0FD7C5DAB33268FF5BB4048C7036B50CF418F245734FA67B857D741CB3F5864D` |

감사 상태는
`PASS_OLD_SESSION_KNOWN_CLOSED_EXTERNAL_NORMAL_BYE_NEW_GENERATION_UNCONNECTED`다.
수집 전후 `ValidateOnly`, PS5 AST와 정적 시험이 통과했고 고정 파일 해시는 변하지
않았다. 새 세대의 DB 원격 주소·IP·로컬 임시 포트는 기록하지 않았고, 허용된 DB
포트 종류와 30001/9339 부재만 안전 projection으로 남겼다.

## 고정 산출물

| 항목 | 크기 | SHA-256 |
|---|---:|---|
| `round-plan.json` | 37,950 bytes | `EEB5C9102D5A797EB459E79F29932E58E921F33C957842477FD9E0BF993E4EB4` |
| `round-m-r2-confirm.ps1` | 67,779 bytes | `DDEA4081FAECD68ADF7BA1E490FB380EE118115024AB98249FAC1CCC79F00084` |
| 운영/시험 계획 빌더(서로 byte-identical) | 33,459 bytes | `C73BEBFE52A3851F4F47DA82F1667B3412780B19A156E5225680EB956C2CE21A` |
| 승인 빌더 | 5,391 bytes | `6EDDCD19A4888447A30EABEF34B6100C31842C1986E00CF4804174A47D0647FC` |
| 정적 시험 | 9,957 bytes | `8947CEE9004C66A0239FFDCE56EA4EC12D4CA090ABAFB2DE1CAFD7793513E0C0` |
| 승인 문구 템플릿 | UTF-8 text | `11E5EEF315895C20C906ECED4DECB920CC70F04A7BF376010FDA833328210AD4` |
| 이 계획에 채워진 전체 승인 문구 | UTF-8 text | `2DA9CC53A73FC40A96269491A1E7FA29221EFFB0281BEB67B9D68A70707FDD57` |

운영 산출물은 Git 제외 경로
`artifacts/pgm-evidence/MBNWEB-20260712-M-R2`에 있다. 계획 JSON은 엄격한
UTF-8 파싱에 성공했고, Windows PowerShell 5 정적 검사와 승인 빌더·확인 도우미의
`ValidateOnly`가 모두 통과했다. 검증 전후 고정 파일 해시는 동일하고 M-R2
승인·실행·confirm dispatch·complete·result 파일 5개는 모두 없다.
감사 중 발견된 이전 계획 35,606 bytes,
`57225B876FEAD5784CE0D5F9DEF0A5885A802DEC14015AAC638E9120CB61E5AB`은
승인 금지 superseded 증거로만 보존한다.

## M-R1과 현재 상태 결박

| 항목 | 기대값 |
|---|---|
| M-R1 계획 | 17,466 bytes, `E5D12936867203B83306D0B6D98AC8347DD7E5914CCAEB941528CD866569BC77` |
| M-R1 승인 | 2,707 bytes, `0019696B9354885BB9157F689AAD537E62C9AEB8A8F50C49C1D0629E26CA9B6F` |
| M-R1 실행 marker | 4,912 bytes, `E188D8E540644B94DD105D8A10CBF5A614563190A8D0FED1099AFE1BACFBE496` |
| M-R1 닫기 요청 journal | 425 bytes, `767648452A11A7BDC8B272D4BB8F9E4DC8D629228938EA682B0C4D60A4C7DE23` |
| M-R1 결과 | 1,914 bytes, `6543B53F1D5D99B707FC2E04A1F09EA61E39714FE468FA7CF029C85A720851C9` |
| M-R1 명령 | `CloseMainWindow=1`, `Invoke=0`, retry·송출·DB·직접 CDP/K3D=0 |
| 앱 / CDP | PID 37916 / 34988, 기존 시작 세대와 `127.0.0.1:9339` 유지 |
| Tornado2 | PID 6972, 기존 시작 세대와 `0.0.0.0:30001` listener 유지 |
| 앱↔Tornado TCP | `127.0.0.1:23210 <-> 127.0.0.1:30001` 정확히 두 행 |
| Network Monitoring | 142,844 chars, `839882172C79211517E4C3C81EBF95E65B322B6418B086985EE13E917A3F5A37` |
| Round M 이후 증가분 | HELLO 요청·성공 각 1회뿐, 266 chars, `3B4B7946CB345B121880CC1EF904E429A16A367F3AF6DD23FCFFDEF559EAAFF4` |
| M-R1 닫기 뒤 증가분 | 0 chars, BYE·송출 명령 0 |
| PGM | 8×8 표본 64개 RGB 최대값 0, 검은 화면 |
| 안전 부재 경로 | Round M runtime/prepare/config/capability 6개와 M-R1 confirm 파일 2개, 총 8개 |

## 정확한 UIA 구조

계획은 다음 9개 요소의 RuntimeId, PID, FrameworkId, ClassName, ControlType, Name,
AutomationId, Enabled, Offscreen, 경계 사각형과 부모·형제 관계를 모두 고정한다.
정규화된 구조의 SHA-256은
`39253843B55682066E786AA9217BA5420BC7ED97E9BBC0E38A822A36C5696E75`이다.

```text
DesktopChildSiteBridge Pane (Win32)
└─ InputSite Pane (XAML)
   ├─ generic Popup Window: Name=Popup
   └─ dialog Window: Name=프로그램 종료
      ├─ ContentScrollViewer
      │  ├─ Text: 프로그램 종료
      │  └─ Text: 프로그램을 종료하시겠습니까?
      ├─ Button: 종료, AutomationId=PrimaryButton
      └─ Button: 취소, AutomationId=CloseButton
```

dialog의 Button은 위 두 개, Text는 위 두 개만 허용한다. 앱 전체에서 `종료` 이름의
Button은 하나여야 하고, PrimaryButton은 활성·화면 표시·InvokePattern 지원 상태여야
한다. pending, prepared, outcome-unknown 또는 방송 경고 문자열이 나타나면 확인하지
않는다. InputSite의 전체 직접 자식 RuntimeId 집합은 정확히 9개, 그중 Window
부분집합은 generic Popup과 dialog Window 2개로 고정한다.

## 승인 후 허용되는 유일한 흐름

1. 계획, M-R1 증거, 프로세스·창·listener 세대, TCP, Network 로그, 검은 PGM과
   정확한 UIA 구조를 모두 읽기 전용으로 재검증한다.
2. 승인 파일과 계획·도우미 해시를 확인하고 내구성 실행 marker를 기록한다.
3. 전체 상태와 승인 freshness를 다시 확인한 뒤 confirm may-have-issued journal을
   `CreateNew`, `WriteThrough`, `Flush(true)`로 먼저 기록한다.
4. journal 뒤 M-R1/M-R2 control file, 전체 외부 상태, UIA RuntimeId와 구조 해시,
   계획·도우미·승인을 다시 확인한다. 새로 얻은 정확한 PrimaryButton element의
   UIA `Invoke`를 한 번만 호출한다.
5. 앱·CDP·9339 listener와 기존 active TCP가 사라지고 Tornado2 세대·창·30001
   listener가 유지되는지 확인한다. Network suffix는 BYE 요청 정확히 1회와 성공
   0~1회만 허용하며 PGM은 계속 검은 화면이어야 한다.

`CloseMainWindow` 재호출, 다른 UI Invoke, 좌표 클릭·키 입력, PREPARE, TAKE IN,
NEXT, Page NEXT, TAKE OUT, DB write, 재연결, 재실행, 직접 CDP/K3D 명령,
강제 종료, 재시도와 Tornado2 창 복원은 허용하지 않는다. 어느 경계든 달라지거나
결과가 불명확하면 추가 명령 없이 즉시 중단한다.

## 정확한 승인 문구

아래 한 줄을 그대로 승인해야 한다. 계획 해시가 다르면 승인 효력이 없다.

> 회차 MBNWEB-20260712-M-R2의 확인 전용 계획 SHA-256 EEB5C9102D5A797EB459E79F29932E58E921F33C957842477FD9E0BF993E4EB4을 승인한다. M-R1 close-result SHA-256 6543B53F1D5D99B707FC2E04A1F09EA61E39714FE468FA7CF029C85A720851C9가 outcome-unknown 상태이고, 운영체제 정상 닫기 요청 CloseMainWindow가 이미 정확히 1회 소비되었으며 확인 Invoke는 0회임을 확인한다. 현재 K3D 라이선스가 유효하고 Tornado2 PID 6972가 지정된 주 프로그램임을 확인하며, 현재 실행 중인 MBN_STOCK_WEBVIEW PID 37916, 시작 시각 2026-07-12T18:59:06.3837959Z에 이미 열려 있는 '프로그램 종료' 대화상자가 '프로그램을 종료하시겠습니까?'라는 중립 문구와 '종료' PrimaryButton 및 '취소' CloseButton만 정확히 표시할 때, 기존 '종료' 확인 Invoke 정확히 1회와 그 정상 종료 과정에서 발생하는 DISCONNECT/BYE 최대 1회만 승인한다. CloseMainWindow 재호출, 다른 UI Invoke, PREPARE, TAKE IN, NEXT, Page NEXT, TAKE OUT, DB write, 재연결, 재실행, 직접 CDP/K3D 명령, 프로세스 강제 종료, 재시도 및 Tornado2 창 복원은 승인하지 않는다. 사전 조건이 하나라도 달라지거나 결과가 불명확하면 추가 명령 없이 즉시 중단한다.
