G7 증명과 G8 clean-head 승격 준비

This commit is contained in:
Yun Chan 2026-08-09 18:22:03 +09:00
parent 94c681d450
commit 5221f79e3f
52 changed files with 6876 additions and 506 deletions

View file

@ -87,15 +87,28 @@ powershell -NoProfile -ExecutionPolicy Bypass -File scripts\start-tailscale-runt
공개 API 복구 스크립트는 `docs/ops/public-runtime-watchdog.md`가 runbook이다. 로컬 개발 서버와 별개로
prod API 8001, web preview 5174, engine gateway 9099, cloudflared tunnel을 검사한다.
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\watch-public-runtime.ps1 -CheckOnly
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\install-public-runtime-task.ps1 -RunNow
```
- shared branch worktree의 watchdog/start script를 직접 실행하지 않는다. 승인된 clean commit의 detached release
worktree를 만들고, 그 root 내부 registrar에 `-StableSourceRoot`를 명시해 두 task를 승격한다.
- Scheduled Task는 현재 Windows 사용자 기준 `AtLogOn` + 반복 watchdog이다. 사용자 로그인 전 headless boot service가 아니다.
- secret은 task 인자에 넣지 않는다. API secret은 `apps/api/.env`, cloudflared/Claude CLI credential은 사용자 profile에 둔다.
$releaseRoot = 'D:\workspace\vignette-public-runtime-<commit>'
$bootRegistrar = Join-Path $releaseRoot 'scripts\register-boot-task.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $bootRegistrar -StableSourceRoot $releaseRoot
$watchdogInstaller = Join-Path $releaseRoot 'scripts\install-public-runtime-task.ps1'
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $watchdogInstaller -StableSourceRoot $releaseRoot -IntervalMinutes 5
- `VignettePublicRuntime`은 로그온 Docker/DB 복구, `VignettePublicRuntimeWatchdog`은 로그온+5분 반복 health/recovery다.
- 두 task action은 release root와 Git commit/tree, boot 또는 watchdog SHA-256, start script SHA-256을 고정한다.
등록 뒤 action marker와 working directory를 읽어 검증하기 전에는 `RunNow`를 호출하지 않는다.
- secret은 task 인자에 넣지 않는다. API secret은 stable release의 `apps/api/.env`, cloudflared/Claude CLI credential은
사용자 profile에 둔다. `.env` 내용을 console이나 evidence에 출력하지 않는다.
- 아직 DNS가 없는 future host는 기본 검사에 넣지 않는다. `api-vnet.18ka.net`처럼 실제로 열린 뒤에만 `-AdditionalPublicHealthUrls`로 명시 추가한다.
- 완료 판정은 parser/check-only가 아니라 실제 재부팅 또는 로그오프/로그온 뒤 `Get-ScheduledTaskInfo`, watchdog 로그의 `restart verified`, public health, 인증된 public `/turn` smoke까지 한 세트로 남겨야 한다.
- `watch-public-runtime-hidden.vbs`는 source를 직접 실행하지 않고 pin marker를 검증한 등록 task만 trigger한다.
- 완료 판정은 parser/check-only가 아니라 실제 재부팅 또는 로그오프/로그온 뒤 `Get-ScheduledTaskInfo`, stable release의
watchdog 로그, public health, process cwd/Git provenance, 인증된 public `/turn` smoke까지 한 세트로 남겨야 한다.
- detached worktree 생성, `.env`/`node_modules` 준비, source pin 검증, read-only `-CheckOnly` 전체 명령은 runbook을 따른다.
- G7 공개 증거 승격은 routine API-only 복구와 다르다. `-RequireFreshPublicProvenance` + `-ForceApiRestart`
API와 exact-config cloudflared를 둘 다 새 PID로 교체하고 commit/tree·Python/cloudflared/config SHA와 safe receipt를
결속한다. 이 모드에서 `-SkipCloudflaredRestart`는 금지되며, 정확한 명령은 runbook의 G7 fresh 절을 따른다.
### 수동 기동(대안)

View file

@ -20,7 +20,7 @@ Vignette 저장소의 모든 검증 수단(백엔드 단위 테스트, 웹 타
| API 타입 생성 체크 | `apps/web` | `npm run check:api-types` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | pass |
| 웹 타입체크 | `apps/web` | `npm run typecheck` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | pass |
| 웹 빌드 | `apps/web` | `npm run build` | 불필요 | 불필요 | 불필요 | 불필요 | 불필요 | pass |
| Playwright E2E(전체) | `apps/web` | `npm run e2e` | **필요(+시드)** | **필요** | 자동기동 | 일부만 | **필요** | 현재 수집 610 tests / 44 files · 현 작업트리 전체 GREEN 미검증 |
| Playwright E2E(전체) | `apps/web` | `npm run e2e` | **필요(+시드)** | **필요** | 자동기동 | 일부만 | **필요** | 현재 수집 614 tests / 44 files · 현 작업트리 전체 GREEN 미검증 |
핵심 원칙: **단위 테스트(pytest)와 타입체크/빌드는 외부 서비스 없이 단독 실행된다.**
**E2E만 풀스택(DB+API+웹+브라우저)을 요구한다.** 아래 각 절에서 근거와 절차를 설명한다.
@ -271,7 +271,7 @@ VITE_API_BASE=http://127.0.0.1:8000 npm run e2e # 프록시 대신 API
### 3.6 실측 테스트 개수 (현재)
2026-08-07 `npx playwright test --list` 기준 **현재 수집 610 tests / 44 files**다.
2026-08-09 `npx playwright test --list` 기준 **현재 수집 614 tests / 44 files**다.
이 숫자는 수집량이지 통과량이 아니다. 현 작업트리 전체 604개 완주는 아직 증거가 없으며,
과거 전체 GREEN 기록과 이번 focused/release gate 결과를 구분해 적는다.
@ -401,11 +401,11 @@ VITE_API_BASE=http://127.0.0.1:8000 npm run e2e # 프록시 대신 API
```powershell
C:\Users\encep\AppData\Local\Programs\Python\Python311\python.exe -X utf8 `
scripts\soak-public-voice-websocket.py --preflight-only `
--expected-stt-provider deepgram --expected-stt-model nova-3 `
--expected-tts-provider <승인된-provider> --expected-tts-model <승인된-model>
--expected-stt-provider local_whisper --expected-stt-model small `
--expected-tts-provider melotts --expected-tts-model melotts-korean
```
50분 full soak는 같은 기대값에 `--duration-seconds 3000`, `--microphone-device <명시-장치>`,
50분 유효 공통창 full soak는 같은 기대값에 `--duration-seconds 3120`, `--microphone-device <명시-장치>`,
`--confirm-physical-capture`를 추가하고 사용자가 실행 직전에 물리 캡처에 명시 동의한 경우에만 실행한다.
- 2026-08-07 G7 external-proof readiness: Session 첫 음성 사용은 서버 30일·원음 미보존 consent ledger가
성공하기 전 `getUserMedia`와 voice WebSocket을 시작하지 않는다. controlled provider와 synthetic stream을
@ -414,9 +414,15 @@ VITE_API_BASE=http://127.0.0.1:8000 npm run e2e # 프록시 대신 API
runner/checker와 release gate contract **31 passed**, typecheck·API type
contract·Ruff·py_compile을 통과했다. `soak-public-voice-websocket.py` v4, `/admin/voice-runtime`,
`capture-g7-runtime-evidence.py`, `capture-g7-topology-evidence.py`, independent human-held-out evaluator를
`check-g7-external-proof.py`가 같은 public host·겹치는 50분 시간창으로 묶는다. 실제 마이크·운영 Deepgram·
실제 참가자 evidence는 없으므로 G7은 BUILD다. 상세는
`check-g7-external-proof.py`가 같은 public transport host·겹치는 50분 시간창으로 묶는다. 실제 마이크·운영
local provider·실제 참가자 evidence는 없으므로 G7은 external GATE다. 상세는
`ops/outcome-os-g7-external-proof-readiness-2026-08-07.md`가 소유한다.
- 2026-08-09 G7 external-proof P0: production runner exit를 canonical checker 0·`gate_closed=true`에 묶고,
browser Origin allowlist와 API/WSS/admin/topology host·scheme을 분리했다. capture 최소 3,120초와 세 runtime
artifact 공통 3,000초, detached-clean commit/tree·runner/collector/checker SHA·`psutil==6.1.1`, fresh
API/cloudflared PID provenance receipt를 fail-closed로 고정했다. runner/checker/topology 86/86,
launcher/sidecar 80/80, G7 통합 166/166, API 921, gateway 58을 통과했다. 이 수치는 실제 물리 마이크·human pack을
대체하지 않으므로 G7은 external GATE다.
- 2026-08-07 G7/G8 시각 QA: 데스크톱·Pixel 5에서 focused **16/16**, typecheck·build·cosmetic-filter를
통과했다. G8 승인 차단 이유를 `title` 의존에서 상시 문구·`aria-describedby`·semantic form/Enter 제출로
바꾸고, G7 이벤트 최소 24×24px와 시간축 키보드 포커스를 수치 회귀로 고정했다. 상세는