8 Commits

Author SHA1 Message Date
EJClaw
81e0271b69 feat: 저장 위치를 첫 실행 때 고르고 기억한다
Some checks failed
Windows / verify (push) Has been cancelled
모델이 티어에 따라 2~17GB 를 차지하는데 %APPDATA% 에 박혀 있어서 C 드라이브가
좁은 사람은 손쓸 방법이 없었다. 처음 켤 때 한 번 묻고, 그 선택을 기억하고,
설정에서 바꿀 수 있게 한다.

닭과 달걀 문제가 하나 있다 — "어디에 둘지" 는 사용자가 정하는데 그 선택 자체는
고정된 곳에 적어둬야 다음 실행에 찾을 수 있다. 그래서 OS 표준 폴더에는 위치를
가리키는 쪽지(location.json) 한 장만 두고, 내용물은 전부 고른 폴더에 둔다.

- storage.py 신설: 쪽지 읽기/쓰기, 경로 검증, 여유 공간, 데이터 이동
- config.py 의 CONFIG_PATH 를 config_path() 로 바꾼다. import 시점 상수라
  위치를 바꿔도 옛 경로를 계속 가리켰다
- 위치가 정해지기 전에는 파일 로그를 열지 않는다. 열면 고르지도 않은 기본
  폴더가 만들어지고 거기에 로그가 남는다
- 이전 버전 사용자에게는 묻지 않는다. 기본 위치에 쓰던 흔적이 있으면 그대로
  쓴다 — 같은 자리를 다시 고르는 헛수고를 시킬 이유가 없다
- 고른 디스크가 빠져도 죽지 않고 기본 위치로 물러난다
- 위치를 바꿀 때 받아둔 모델을 옮길지 물어본다. 수 GB 라 창이 얼어붙지
  않도록 별도 스레드에서 옮긴다
- windows_smoke 에 이 화면 렌더링 점검을 추가하고, 스크린샷을 호스트로
  회수한다. 경로 표기와 디스크 조회는 OS 마다 다르게 도는 부분이다
2026-09-26 00:57:04 +09:00
EJClaw
4fd8fabcb8 build: 포터블 exe 에서 빠져 있던 프로그램별 캡처 도우미를 복구
Some checks failed
Windows / verify (push) Has been cancelled
livesub_capture.exe 가 없으면 포터블 빌드는 그대로 성공하되 프로그램별
캡처가 장치 전체 캡처로 조용히 폴백된다. 핵심 기능이 빠진 exe 가 나오는데
빌드는 PASS 로 보이는 조합이라 그대로 릴리스될 뻔했다.

- win-ci VM 에 VS 2022 Build Tools(C++)를 깐다. WASAPI 프로세스 루프백
  헤더와 WRL 은 Windows SDK + MSVC 에만 있어서 cmake 만으로는 못 만든다.
- 검증 순서에 native_capture 단계를 windows_smoke 앞에 넣는다. 뒤에 두면
  smoke 와 spec 이 둘 다 "없음"으로 통과해 버린다.
- pyinstaller 단계가 거짓 PASS 를 내던 것을 고친다. 앞 회차의 exe 가
  실행 중이면 PermissionError 로 빌드가 죽는데, 남아 있는 옛 exe 때문에
  Test-Path 검사는 통과했다. 빌드 전에 프로세스를 죽이고 build/dist 를
  지우며 PyInstaller 종료코드도 확인한다.
- 통과한 exe 를 호스트로 회수한다. serve-host.py 는 32MB 상한이라 exe 를
  413 으로 튕겼다. 상한을 올리고 조각으로 받아 디스크에 바로 쓰며,
  .part 로 받아 완료 후 옮겨 반쪽 파일이 결과물로 남지 않게 한다.
- .gitignore 의 네이티브 산출물 경로가 예전 이름(hearo)이라 빌드한
  exe 가 무시되지 않던 것을 livesub 로 고친다.
2026-09-26 00:24:31 +09:00
EJClaw
ca096a69c3 ci: 회수한 증거 파일의 한글이 깨지던 것 수정 + 문서화
Some checks failed
Windows / verify (push) Has been cancelled
[Console]::OutputEncoding 을 UTF-8 로 두지 않으면 PowerShell 이 자식
프로세스 stdout 을 콘솔 코드페이지(LTSC en-US = 437)로 읽는다. python 쪽은
PYTHONUTF8=1 로 UTF-8 을 내보내니 한글이 전부 깨지고, 회수한 증거 파일의
실패 메시지를 읽을 수 없었다(실제로 첫 수집본의 한글 트레이스백이 그랬다).

docs/WINDOWS-TESTING.md 에 증거 채널(POST /artifact -> results/)과
sync.sh <sha> 재검증 절차를 적었다.
2026-09-25 23:44:00 +09:00
EJClaw
0a1389a1d9 ci: 검증 대상 리비전을 명시하고 그것이 재실행 트리거가 되게 한다
Some checks failed
Windows / verify (push) Has been cancelled
게스트 agent 는 stage2.ps1 의 해시가 바뀔 때만 다시 돈다. 그래서 커밋을
푸시해도 재검증이 안 걸렸고, 지금까지는 주석에 "rev2" 같은 문구를 넣어
해시를 억지로 바꿨다. 무엇을 검증한 결과인지도 모호했다.

stage2.ps1 에 $TargetRev 를 두고 `./sync.sh <sha>` 가 그 값을 박아서
배포한다. 검증 요청(= 리비전 지정)이 그대로 재실행 트리거가 되고,
움직이는 origin/main 대신 지정한 커밋을 reset --hard 로 고정해 본다.
2026-09-25 23:39:45 +09:00
EJClaw
a66eedee8b ci: win-ci 검증 출력을 호스트 파일로 회수한다 (증거 기준선)
Some checks failed
Windows / verify (push) Has been cancelled
VM 을 만든 이유가 "리눅스에서 통과한 게 Windows 에서 깨지는 것을 재현
가능하게 본다" 인데, 정작 실패 트레이스백이 호스트에 한 줄도 안 남았다.
로그 채널은 마지막 몇 줄만 흘렸고(Select-Object -Last 30), serial.log 는
VM 이 뜰 때마다 truncate 되고, guest.log 는 stage2 가 다시 돌 때만 채워진다.
그래서 실패 내용을 화면에서 읽어 옮겨 적는 상태였고 — 고친 뒤에 고쳐졌다는
것을 증명할 기준선이 없었다.

- serve-host.py: POST /artifact/<name> 추가. results/<name> 에 파일로 저장
  (경로는 basename 으로만 취하고 32MB 상한)
- stage2.ps1: Step 이 각 단계의 출력 전문을 StreamWriter(AutoFlush)로 받아
  호스트로 업로드한다. 중간에 예외로 죽어도 거기까지는 남는다.
  출력 자르기를 없애고 pytest 는 --tb=long, 검증 리비전을 박은
  summary.log 도 함께 올린다
- sync.sh: 스크립트만 /home/claude/win-ci 로 반영한다. build.sh 를 다시
  돌리면 지워둔 Windows ISO 4.8GB 를 다시 내려받는다

첫 수집 결과(rev 162540b)로 실제 원인 두 개를 특정했다.
2026-09-25 23:38:48 +09:00
EJClaw
89b0ee0cf7 ci: win-ci VM 을 재부팅 후에도 살아나게 + VM 안 자체 검증 절차
Some checks failed
Windows / verify (push) Has been cancelled
트랜지언트 유닛은 재부팅에 안 남는다. 러너 호스트가 재부팅마다 사라지면
CI 가 조용히 대기 상태가 되므로 영구 user 유닛으로 박는다 (linger=yes 라
로그인 없이도 올라온다). cgroup/CPU 상한은 트랜지언트 때와 동일하다.

stage2 에는 러너 등록 토큰 없이도 워크플로와 같은 단계를 VM 안에서 직접
돌리는 검증을 넣었다. 첫 실행에서 실제로 결함 하나를 잡았다.
2026-09-25 23:03:40 +09:00
EJClaw
ae295dc308 fix: 무인 프로비저닝이 통째로 안 돌던 인코딩/파이프라인 결함 3건
실제 설치에서 드러난 것들이다. 셋 다 증상이 원인과 전혀 안 닮아서 기록해 둔다.

1) provision.ps1 이 1행부터 파싱 실패 - 'Missing closing }'
   Windows PowerShell 5.1 은 BOM 없는 .ps1 을 ANSI(CP1252)로 읽는다.
   한글 주석의 UTF-8 바이트가 CP1252 에서 스마트따옴표(0x93/0x94 = " ")로
   변하고, 파서가 그걸 문자열 시작으로 보고 뒤를 전부 삼킨다.
   -> build.sh 가 ISO 에 넣을 때 UTF-8 BOM 을 붙인다.

2) stage2.ps1 의 1행이 주석으로 인식되지 않음
   agent 가 받은 본문에 BOM 이 있으면 Set-Content -Encoding UTF8 이 BOM 을
   한 번 더 붙여 BOM 이 두 개가 된다. PowerShell 은 첫 개만 벗겨내고 남은
   U+FEFF 때문에 '#' 이 줄 맨 앞이 아니게 된다.
   -> agent 가 TrimStart(U+FEFF), 서버는 charset=utf-8 을 명시한다.

3) Git 설치가 'Cannot convert System.Object[] to System.String' 로 실패
   Log 가 Write-Output 이라 함수 안에서 부르면 그 함수의 반환값에 로그가
   섞인다. Get-File 이 배열을 돌려주니 Start-Process 가 죽었다.
   -> Log 를 Write-Host 로 바꿨다.

덤으로 시리얼/HTTP 로그의 한글이 '?' 로 깨지던 것도 고쳤다 (SerialPort 기본
인코딩이 ASCII). 그리고 러너 토큰이 없어도 워크플로와 같은 단계를 VM 안에서
직접 돌리는 검증 절차를 stage2 에 붙였다.
2026-09-25 22:50:08 +09:00
EJClaw
e41d0cb441 ci: .9 안 Windows CI VM 무인 구축 자동화
Windows 설치 화면을 사람이 클릭할 수 없으므로 전 과정을 무인으로 짰다.
autounattend.xml 이 설치와 OOBE 를 끝내고, provision.ps1 이 virtio 드라이버를
오프라인으로 넣어 네트워크를 살리고, 상주 agent.ps1 이 호스트 HTTP 에서
stage2.ps1 을 받아 Git/pwsh7/Python/Node/CMake/act_runner 를 설치한다.

설치 내용을 ISO 에 박지 않고 호스트가 HTTP 로 내려주는 구조로 한 이유는
ISO 를 한 번 구우면 못 고쳐서, 한 줄 고칠 때마다 Windows 재설치가 되기
때문이다. stage2.ps1 만 고치면 게스트가 20초 안에 반영한다.

- 시스템 디스크는 SATA. virtio-blk 로 하면 Setup 이 디스크를 못 봐서
  WinPE 드라이버 주입이 필요해진다
- VM 은 systemd --user 트랜지언트 유닛으로 띄워 봇 cgroup 밖에 둔다
  (MemoryHigh=16G 안에 8G VM 이 들어가면 봇이 OOM 으로 죽는 전례)
- Node 포함. act_runner host 모드가 JS 액션을 PATH 의 node 로 돌린다
2026-09-25 22:13:55 +09:00