# G7 external proof readiness — 2026-08-07 ## 판정 G7은 **내부 구현 DONE · external GATE**다. 이번 변경은 물리 마이크나 운영 provider를 사용한 실증이 아니라, 외부 증거가 들어왔을 때 synthetic·preflight·짧은 probe로 잘못 닫히지 않도록 종료 게이트를 실행 가능한 네 artifact 계약으로 만든 것이다. ## 이번에 닫은 내부 범위 - Session의 첫 음성 사용은 인앱 설명과 명시 동의를 요구한다. 서버의 30일·원음 미보존 동의 원장 기록이 성공하기 전에는 `getUserMedia`와 `/voice/ws`를 시작하지 않는다. 거절·원장 실패·지연 권한 응답·일시정지·회기 전환은 텍스트 대안을 유지하고, 뒤늦게 도착한 MediaStream의 track을 즉시 종료한다. 숨은 Space 단축키는 제거하고 안내 가능한 `Alt+M`만 남겼다. - public WSS runner v4는 매 turn마다 interim 1개 이상과 speech-final 정확히 1개를 요구하고, 첫 interim·speech-final latency와 전체 합계를 metadata-only evidence에 기록한다. 장치 열거와 캡처는 `--confirm-physical-capture` 없이는 시작하지 않는다. - `/admin/voice-runtime`은 단일 API worker의 process RSS/peak RSS/CPU/thread/FD와 WebSocket, provider session, route audio buffer, streaming event queue, overflow/fallback/error high-water를 인증된 관리자에게만 반환한다. 원음·축어록·session ID·provider payload는 저장하지 않는다. production Docker Uvicorn WebSocket ingress queue는 `--ws-max-queue 4`로 고정했다. - Linux topology sampler는 exact Compose project/service, container ID, image digest, init PID, start/restart, cgroup path를 매 sample 전후 재검증한다. cgroup v2, `/proc`, parsed Docker stats, endpoint를 폐기한 host TCP queue/retransmit의 50분 high-water를 만들 수 있다. - 누적 high-water를 이번 실행의 부하로 오인하지 않도록 Linux Compose API/container는 증거 시작 120초 이내의 동일 인스턴스여야 한다. Windows host mode는 detached-clean commit/tree, runner/collector/checker SHA, `psutil==6.1.1`, 새 API/cloudflared PID/start/exe·command SHA/실제 cwd를 매 sample 전후 검증한다. checker는 voice/runtime/topology 세 artifact의 **공통 시간창이 3,000초 이상**인지 재계산한다. - 독립 human-labeled held-out voice-gain 계약은 raw audio·transcript·synthetic pack을 거부하고, held-out 공개 전에 끝난 사전등록·동의·participant split·model artifact·blind independent labeler provenance를 요구한다. production gate는 최소 31명(held-out 30명 외 calibration split 포함), 양 조건이 모두 관측된 완전 paired 50회기/150축, ICC(A,1) 0.75, **필수 categorical κ 0.70**, gain 0.01, participant-cluster bootstrap 10,000회의 95% CI lower `> 0`을 재계산한다. 한 조건이라도 결측이면 양 조건을 모두 최대오류로 처리해 baseline-only 결측이 candidate gain을 부풀리지 못하게 한다. - `scripts/check-g7-external-proof.py`는 같은 public host와 겹치는 시간창의 public soak, process-local runtime sampling, pinned topology sampling, independent human-gain pack 네 가지를 모두 통과시켜야 성공한다. G7 release gate는 이 checker 증거가 있을 때만 `satisfied-by-validated-g7-proof`로 바뀔 수 있다. ## 검증 - API 전체 `921 passed`, gateway `58 passed`, API voice 통합 `71 passed`. - current G7 scripts `86/86`, API human evaluator `11/11`; Ruff·`py_compile`·`git diff --check` 통과. - Web typecheck와 API type contract 통과. - `voice-success.spec.ts` chromium single-run `2/2` 통과. 동의 원장 응답을 의도적으로 지연한 동안 `getUserMedia=0`, voice WebSocket `0`을 확인했고, 성공 뒤 각각 정확히 1회였다. - 모든 브라우저 음성 테스트는 synthetic MediaStream과 controlled provider만 사용했다. 실제 장치 열거·캡처는 수행하지 않았다. - 내부 hardening release SHA `a8c27b0aadcb9dacea86c4be5e62e19277b9cc2678ebca51aa02998d2c2d1a0d`를 격리 NAS에 승격했다. 첫 clean-candidate 실행은 오래된 동의 fixture를 23/24에서 차단하고 원격을 변경하지 않았으며, 실제 동의 순서로 고친 뒤 24/24·OpenAPI 124·auth 401·G0~G8·NAS browser SSE→DB review를 통과했다. 이 증거에서도 물리 마이크는 사용하지 않았다. ## 실제 종료 때 필요한 네 artifact 1. `soak-public-voice-websocket.py` v4의 운영 기본값 `local_whisper`/`melotts`와 정확히 일치하는 ready metadata, authenticated public WSS· 명시 동의 물리 마이크 50분 양방향 `passed` evidence. 2. 같은 시간창에 `capture-g7-runtime-evidence.py`로 얻은 관리자 endpoint worker/Uvicorn queue high-water evidence. 3. 같은 public host·exact images에 `capture-g7-topology-evidence.py`로 얻은 50분 cgroup/proc/Docker/TCP high-water evidence. Cloudflare 내부 큐는 직접 관측 가능하다고 주장하지 않고, public runner의 edge RTT/gap/disconnect/TLS/CF-Ray 증거를 별도 경계로 사용한다. 4. 실제 동의 참가자와 독립 blind labeler로 만든 human held-out voice-gain evidence pack. 네 파일을 `check-g7-external-proof.py`에 넣어 exit 0과 artifact SHA-256을 얻기 전에는 G7을 DONE으로 표시하지 않는다. ## 실행 오케스트레이터 (2026-08-08 추가) 앞의 1~3번은 **같은 public transport host의 공통 3,000초 시간창**이어야 하는데, 지금까지는 운영자가 세 명령을 따로 띄우고 시계를 손으로 맞춰야 했다. 50분짜리 실행에서 한 번 어긋나면 처음부터 다시 해야 한다. `scripts/run-g7-external-proof-window.py`는 production human pack을 **마이크를 열기 전에 먼저 완전 검증**하고, 통과한 경우에만 세 캡처를 동시에 시작한다. 종료 뒤 canonical checker가 같은 pack과 세 runtime artifact를 다시 검증한다. runtime/topology interval 기본값은 child collector 상한과 같은 60초이며, 60초 초과는 시작 전에 차단한다. 사람 데이터 운영자는 52분 실행과 독립적으로 pack을 먼저 검증할 수 있다. `--print-schema`는 authoritative JSON Schema를 출력하고, 오류는 JSON pointer와 유형만 반환해 participant/labeler key·라벨 값·PII를 반사하지 않는다. ```powershell & $py -X utf8 -B scripts/check-g7-human-voice-gain.py --print-schema & $py -X utf8 -B scripts/check-g7-human-voice-gain.py --input ``` ```powershell # 실제 실행 (물리 마이크 50분 + 사람 pack 필요) & $py -X utf8 -B scripts/run-g7-external-proof-window.py ` --wss-url wss://api-vignette.chanpaca.net/voice/ws ` --origin https://vignette.chanpaca.net ` --admin-runtime-url https://api-vignette.chanpaca.net/admin/voice-runtime ` --topology-mode windows-host --repo-root ` --git-sha --git-tree-sha ` --runner-script-sha256 --collector-script-sha256 ` --checker-script-sha256 --psutil-version 6.1.1 ` --api-pid --api-executable-name python.exe --api-executable-sha256 ` --api-cwd --api-listen-port 8001 ` --cloudflared-pid --cloudflared-executable-name cloudflared.exe ` --cloudflared-executable-sha256 --cloudflared-cwd ` --microphone-device "<장치명>" --confirm-physical-capture ` --duration-seconds 3120 ` --human-voice-gain --out-dir <증거디렉터리> ``` 게이트를 **약화시키지 않는다.** CLI로 실증한 주요 fail-closed 경계: | 시도 | 결과 | |---|---| | 동의·장치 없이 운영 실행 | `physical_microphone_consent_required`, exit 2 | | human pack 없이 운영 실행 | `human_voice_gain_pack_required`, exit 2 | | malformed·underpowered·κ 미달·불완전 paired human pack | 물리 캡처 전에 human-pack 오류, exit 2 | | 3,120초 미만 시간창 | `production_window_too_short`, exit 2 | | runtime/topology interval 60초 초과 | child collector 실행 전 interval 오류, exit 2 | | transport host/scheme 불일치 | `hosts_must_match` 또는 scheme 오류, exit 2 | | 허용되지 않은 browser Origin | query/원문을 반사하지 않는 Origin 오류, exit 2 | `--rehearse`는 마이크·사람 없이 **배관만** 확인하는 모드다. soak을 `--preflight-only`로 돌려 장치를 열지 않고, 인자·경로·산출 파일까지 실제로 검증한다. 보고서의 `gate_closed`는 rehearse에서 **항상 false**다. 실제 50분 실행 전에 이걸로 먼저 실패를 뽑아내라. ### 공개 선행 조건 — 2026-08-09 완료 공개 API/cloudflared는 detached-clean `b34623f3…`·tree `32cc85c7…`에서 fresh 승격됐다. 공개 OpenAPI 126, `/admin/voice-runtime`, `local_whisper/small`, `melotts/melotts-korean`, Uvicorn WS queue 4와 receipt `9f8d1941…a21bf` passed를 확인했다. watchdog·로그온 task도 같은 stable root에 source pin돼 명시 실행 결과 0이다. 30초 `--rehearse`는 authenticated WSS ready/ping/close1000, runtime 7 samples, Windows topology 7 samples를 모두 통과했다. evidence는 `physical_capture=false`이며 UUID/email literal 0이다. 이 리허설은 실제 물리 마이크와 human pack을 대체하지 않는다. **판정을 미인증 HTTP 상태로 하지 않는다.** Cloudflare 앞단이 자동화 클라이언트에게 존재하지 않는 경로까지 포함해 **모든 경로를 403(error code 1010)** 으로 돌려주기 때문에, 상태 코드로는 "배포 누락"과 "edge 차단"을 구분할 수 없다. 처음엔 404/401 판정으로 짰다가 이 사실을 확인하고 **OpenAPI spec의 `paths`만 authoritative하게 쓰도록** 고쳤다. 회귀에 그 이유를 테스트로 남겼다. 따라서 남은 G7 실행 순서는 이렇다. 1. 독립 연구팀이 실제 human pack을 작성하고 standalone validator를 통과시킨다. 2. 사용자가 정확한 마이크 장치를 고르고 3,120초 물리 캡처에 명시 동의한다. 3. production runner로 human pack을 재검증한 뒤 mic/runtime/topology 동시 창을 실행한다. 4. canonical checker exit 0과 `gate_closed=true`를 확인한다. 기대 provider 기본값은 2026-08-08 결정에 맞춰 `local_whisper/small` / `melotts/melotts-korean`이다 (근거: `../decisions/local-voice-stack.md`). current G7 scripts는 86/86, API human evaluator는 11/11이다. production exit 0은 `checker_returncode == 0 && gate_closed is true`에 결속되며 rehearse는 성공해도 gate를 닫지 않는다.