GPU 는 한 VM 만 독점한다 — 컨슈머 NVIDIA 는 vGPU/SR-IOV 를 지원하지 않아
쪼개 쓸 방법이 없고, 지금 RTX 5050 은 .9(리눅스)에 물려 있다. 따라서 GPU
없는 상시 CI VM 에서는 CUDA·VRAM·4~5티어를 영영 확인할 수 없다.
코드로 우회할 수 없는 제약이므로, 대신 **나중에 GPU 머신이 생겼을 때 그대로
붙도록** 구조를 지금 잡아뒀다. 이 러너를 다른 프로젝트 GPU 테스트에도 쓸
계획이라면 이 구분이 그쪽에도 그대로 적용된다.
windows:host GPU 없는 서버 VM main push 마다 자동
테스트·Windows 경로·오디오→자막·포터블 exe
windows-gpu:host GPU 달린 머신 수동 실행만
CUDA 인식·VRAM 상한·4·5티어·GPU 번역
- windows_smoke.py --gpu
GPU 있는 머신에서만 의미 있는 항목만 모았다. CUDA 가용성, 앱의 GPU 인식,
VRAM 상한이 실제로 걸리는지, torch 필요 티어(4·5)가 열리는지, GPU 로 실제
번역까지. 다른 모드와 달리 **GPU 부재를 치명적 실패로 처리**한다 —
GPU 를 확인하겠다고 부른 작업이 조용히 통과하면 안 되기 때문이다.
- .gitea/workflows/windows-gpu.yml
수동 실행 전용. 러너가 없으면 큐에 쌓이기만 하고 아무 일도 없다.
포터블 CI 와 달리 torch CUDA 빌드를 설치하고, 설치 직후 CPU 빌드가
깔리지 않았는지 확인한다. nvidia-smi 가 없으면 그 자리에서 멈춘다.
- 문서에 두 러너 구조와 GPU 머신 확보 3가지 방안(서버에 GPU 추가 /
.9 에서 옮기기 / 필요할 때만 실물 PC) + 슬롯 확인 명령 추가.
검증: pytest 189개 통과, ruff clean, 두 워크플로 파싱·라벨·트리거 확인,
--gpu 를 torch 없는 환경에서 실행해 의도대로 실패(종료코드 1)하는지 확인
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
RTX 5050 은 PCIe 패스스루로 이 VM(.9)이 독점하므로 Proxmox 에 Windows VM 을
띄워도 GPU 를 못 준다. 그래서 "Windows 검증에 GPU 가 정말 필요한가"를 실제로
재봤다 — GPU 를 완전히 가린 채 점검기를 돌린 결과, 실패한 건 'GPU 인식' 하나뿐이고
그건 이미 경고 처리라 빌드를 막지 않는다. 나머지(단축키·모니터·오디오 열거·
exe 빌드·기동·오버레이 렌더링)는 전부 통과한다. 즉 GPU 없는 서버 VM 으로 충분하고,
CUDA/VRAM 관련은 GPU 가 물려 있는 .9 에서 이미 검증 중이다.
- tests/fixtures/en_callout_16k.wav (139KB)
MeloTTS 로 만든 4.4초 영어 콜아웃. CI 가 실제 음성으로 검증할 수 있게 커밋.
- windows_smoke.py --pipeline
오디오 파일 -> 음성인식 -> 번역 -> 한국어 자막까지 끝까지 확인한다.
부품이 다 통과해도 이어 붙이면 안 되는 경우를 잡기 위한 것.
CPU + 가장 가벼운 티어로 돌려 GPU 없는 VM 에서도 그대로 된다.
실측: 27초, 'Enemy coming from the left, fall back now.'
-> '적 왼쪽에서 오는, 지금 뒤로 물러서.'
음성인식 결과에 핵심 단어가 있는지, 자막에 한글이 있는지까지 검사한다.
- 워크플로에 해당 단계 추가 (30분 타임아웃, 첫 회만 모델 다운로드)
- docs/WINDOWS-TESTING.md 에 서버 VM 구축 절차
Proxmox qm create 예시와 함께, 빠뜨리면 조용히 실패하는 두 가지를 명시:
(1) --audio0 없으면 오디오 장치가 안 잡혀 WASAPI 점검이 실패
(2) 자동 로그온이 없으면 데스크톱 세션이 없어 GUI/스크린샷이 전부 실패
(러너를 서비스로 돌리면 안 되는 실질적 이유이기도 하다)
검증: pytest 189개 통과, ruff clean, 워크플로 11스텝 파싱 확인(bash 0개),
GPU 숨긴 조건에서 점검기 실행, --pipeline 실제 통과
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Windows 호스트 러너에서 bash.exe 는 기본 PATH 에 없다 (Git for Windows 는
Git\cmd 만 PATH 에 등록하고 bash.exe 는 Git\bin 에 있다). OS 확인 단계가
첫 스텝이라 러너를 붙이자마자 "bash not found" 로 죽는다. pwsh 로 바꿨다.
같은 이유로 문서 설치 목록에 Git.Git 과 Microsoft.PowerShell 을 추가했다.
나머지 7개 스텝이 전부 pwsh(7.x) 를 쓰는데 Windows 기본 탑재는 5.1 뿐이라
pwsh 없이는 단계마다 실패한다.
트리거 설명도 실제 on: 설정(main push / workflow_dispatch)에 맞춰 고쳤다.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
리뷰 지적을 확인해보니 두 건은 실제 결함이었다.
1) 점검기가 화면 없는 환경에서 그냥 죽음 (SIGABRT, 종료코드 134)
QT_QPA_PLATFORM 을 "windows" 로 하드코딩해 둔 탓에, 표시할 화면이 없으면
첫 QApplication 생성에서 플러그인 로드에 실패하며 아무 결과도 못 남기고
abort 했다. 점검기가 그렇게 죽으면 존재 이유가 없다.
- 화면이 없으면 offscreen 으로 떨어지게 하고, 이 판단을 Qt import 전에 한다
- QApplication 생성을 _qt_app() 한 곳으로 모음
- 실행 플랫폼을 출력해 리눅스에서 돌아간 경우가 바로 보이게 함
이제 환경변수 없이 돌려도 항목별 판정과 종료코드가 정상으로 나온다.
2) 보안 설명이 과장돼 있었음 — 가장 중요한 수정
"커밋된 워크플로만 실행하니 임의 명령은 불가"라고 썼는데, 나는 이 저장소
main 에 push 할 수 있으므로 워크플로를 고쳐 커밋하면 그 PC에서 원하는
명령을 돌릴 수 있다. 개인 PC를 내주는 판단에 쓰일 설명을 틀리게 준 것이라
그대로 바로잡았다. 실제로 보장되는 것(숨길 수 없음·언제든 끌 수 있음·
계정 권한으로만 동작)만 적고, VM 또는 전용 계정을 권하도록 바꿨다.
서비스 등록(SYSTEM 권한) 안내도 로그온 작업(계정 권한)으로 교체 —
"관리자로 띄우지 말라"는 권고와 모순됐다.
3) 라벨 오타 안전장치 (공식 문서 확인 중 발견)
Gitea 는 runs-on 이 어떤 라벨과도 안 맞으면 실패시키지 않고 기본 우분투
컨테이너에서 돌린다. Windows 검증이 조용히 리눅스에서 돌아가 "통과"로
보일 수 있어, 워크플로 첫 단계에서 RUNNER_OS 를 확인해 막는다.
문서의 등록 라벨도 windows:host 로 명시 (생략 시 기본값이 host 이지만
명시가 낫다 — docs.gitea.com/runner/labels).
4) 트리거 설명 정정: "아무거나 push" -> main push 또는 수동 실행.
검증: pytest 189개 통과, ruff clean, 워크플로 트리거/스텝 파싱 확인,
QT_QPA_PLATFORM 없이 점검기 실행해 abort 없이 종료코드 1 확인
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
개발이 리눅스에서 이뤄지다 보니 Windows 전용 경로는 한 번도 실행해 본 적이
없다. 오디오 캡처, 전역 단축키, 모니터 열거, exe 빌드가 전부 여기 해당하고,
"리눅스에서 다 통과했는데 윈도우에서 안 되더라"가 나올 수 있는 지점이다.
- .gitea/workflows/windows.yml
push 때마다 Windows 러너에서 테스트 -> 스모크 -> 포터블 exe 빌드 ->
빌드된 exe 기동 확인까지 하고 exe·스크린샷을 artifact 로 올린다.
의존성을 packaging/requirements-portable.txt 로 깔아 torch 없는 포터블
조건을 그대로 재현하고, torch 가 섞이면 바로 실패하게 했다.
- packaging/windows_smoke.py
리눅스에서 확인 불가능한 항목만 모은 점검기. WASAPI 장치 열거, 소리 내는
프로그램 열거, 전역 단축키 등록/해제, 실제 모니터 열거, GPU 인식,
사용 가능 티어, 자막 오버레이 실제 렌더링(스크린샷 저장).
한 항목이 실패해도 나머지를 계속 돌려 전체 그림을 한 번에 보여준다.
러너 환경에 따라 없을 수 있는 항목(오디오 장치·보조 exe·GPU)은 경고로만
두고, 코드 문제인 항목만 빌드를 실패시킨다.
- docs/WINDOWS-TESTING.md
러너 등록 절차와, 러너 없이 직접 돌려보는 방법.
러너가 없으면 워크플로는 대기만 하므로 지금 상태에 영향이 없다.
검증: pytest 189개 통과, ruff clean, 워크플로 YAML 파싱 확인,
스모크 스크립트를 리눅스에서 실행해 항목별 판정과 종료코드 확인
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>