Author SHA1 Message Date
oz c92660b514 fix: version neural audio requests for v0.1.1 2026-10-14 07:31:47 +00:00
oz a92b2ba1e9 feat: improve Korean neural voice quality for v0.1.1 2026-10-14 07:15:07 +00:00
193 changed files with 17119 additions and 488 deletions
+21
View File
@@ -0,0 +1,21 @@
# ACCEPTANCE — Find-Word v0.1.1
- [ ] package/UI/index/README/manifest 버전 0.1.1
- [ ] 정확한 크레딧 유지
- [ ] `ko-KR-HyunsuMultilingualNeural`, edge-tts 7.3.1 기반 101개 신규 WAV
- [ ] 24kHz mono 16-bit PCM
- [ ] 모든 WAV 비무음, full-scale peak 없음, 합리적 duration
- [ ] manifest 원문·hash·bytes·duration·provider·voice·prosody·tool version
- [ ] 임시 디렉터리 전체 생성 후 원자 교체
- [ ] bounded retry와 실패 시 기존 자산 보존
- [ ] runtime 외부 TTS/API 요청 없음
- [ ] eSpeak 생성 의존 제거
- [ ] audio provenance와 생성 도구 라이선스·provider 한계 문서
- [ ] 기존 10개 mechanic/100문장/8환경/5SNR/choice+text 보존
- [ ] lint PASS
- [ ] 전체 tests PASS
- [ ] build PASS
- [ ] desktop/mobile browser tests PASS
- [ ] audit high 0
- [ ] `.agent/RESULT-v0.1.1.md`
- [ ] Codex는 commit/push/deploy 미실행
+189
View File
@@ -0,0 +1,189 @@
# Find-Word v0.1.1 — 한국어 neural voice 업그레이드 결과
작성일: 2026-10-14 UTC. worktree: `/home/hermes/worktrees/find-word-v0.1.1`.
브랜치: `fix/v0.1.1-neural-voice`.
입력 `.agent/TASK-v0.1.1.md`, `.agent/ACCEPTANCE-v0.1.1.md` 및 기존 맥락을 읽었다.
입력 문서는 수정하지 않았다. **Git commit/push, main merge, 서버 배포는 실행하지 않았다.**
## 구현 결과
- package·lock·UI·index·README·LICENSE·현재 버전 문서·manifest를 **0.1.1**로 맞췄다.
- 정확한 크레딧 `Designed by OZ at Heat-T Medical Inc.`와 canonical repository
`https://source.ibit.kr/OZ-Group/Find-Word`를 유지했다.
- **Microsoft Edge online TTS**, **ko-KR-HyunsuMultilingualNeural**,
**edge-tts 7.3.1**, rate **-6%**, pitch **-4Hz**로 안내 1개·목표 100개를
모두 실제로 새로 생성했다. 기존 WAV를 재포장하거나 재사용하지 않았다.
- pinned `.venv-audio/bin/python`과 `requirements-audio.txt`로 생성 절차를 고정했다.
전역 Python의 다른 버전으로 fallback하지 않는다. FFmpeg 실측 버전은
`6.1.1-3ubuntu5`이다.
- 임시 MP3를 FFmpeg로 24kHz mono PCM16으로 디코드하고 선형 gain만 적용한다.
파일별 RMS 목표 0.10, 증폭 최대 2배, peak ceiling 0.89. 압축·게이트·음절 편집은 없다.
- 임시 디렉터리에서 101개 전체 검증 후 Linux `renameat2(RENAME_EXCHANGE)`로
단일 원자 교환한다. provider 최대 3회, 1/2초 backoff, 시도당 60초 제한.
변환 실패·검증 실패·중단·원자 교체 실패는 기존 자산을 보존한다.
- manifest에 원문·SHA-256·bytes·duration·RMS·peak와 provider·voice·prosody·버전·
sample rate·생성 시각·실측 도구 버전을 남겼다. 인증 헤더·쿠키·API 키는 저장하지 않는다.
- 기존 생성 도구의 캐시/다운로드/문서/manifest 의존을 제거했다. 기존 v0.1 기록은 보존했다.
- 10개 mechanic, 100문장, 8환경, 5SNR, 객관식·주관식, IME·재생 취소·재청취·
실패 복구 흐름은 기존 소스와 테스트를 보존했다. 앱은 로컬 WAV만 요청한다.
## 구현 전에 확인한 실제 RED → GREEN
RED를 모두 실행한 뒤 구현했다. 생성기의 새 함수 계약은 `NotImplementedError`만
발생시키는 비동작 stub으로 선언했고, 기존 명령 진입점은 RED 때 그대로 두어 import
부작용도 실패로 확인했다. stub에 성공 경로를 미리 구현하지 않았다.
RED는 각 명령 종료 코드 **1**, GREEN은 **0**이다. 실패 로그를 덮어쓰지 않았다.
| 계약 | 실제 RED | 실제 GREEN | 원문 evidence |
| --- | --- | --- | --- |
| UI/package/lock/index/문서 버전 및 pinned 생성·권리 문서 | `npm test -- tests/neural-release.test.ts tests/App.test.tsx -t '0.1.1\|브랜드\|고정 venv'`: 3 failed, 기존 12개는 필터로 제외 | 동일 명령 3 passed | [RED](evidence-v0.1.1/01-version-docs-red.log), [GREEN](evidence-v0.1.1/08-version-docs-green.log) |
| neural provider/voice/prosody/실측 버전, 101개 PCM·원문·hash·bytes·duration | `npm test -- tests/assets.test.ts`: 2 failed. 기존 16kHz·누락 metadata/duration을 실제 검출 | 최종 전체 suite에서 두 계약 모두 통과 | [RED](evidence-v0.1.1/02-assets-red.log), [GREEN](evidence-v0.1.1/11-full-test.log) |
| 원자 교체·초기 공개·bounded retry·timeout·기존 자산 보존·secret redaction·실제 MP3 변환·PCM 검증·import 부작용 | Python unittest 16개 모두 RED (subtest 포함 failures=4, errors=20) | 아래 추가 계약을 포함한 18개 통과 | [RED](evidence-v0.1.1/03-generator-red.log), [GREEN](evidence-v0.1.1/05-generator-green.log) |
| 앞서 생성한 파일 손상 감지, 다른 edge-tts 버전의 외부 요청 전 거부 | 구현 전 전체 18개 RED (subtest 포함 failures=5, errors=21) | `python3 -m unittest discover -s tests/python -v`: 18 passed | [추가 RED](evidence-v0.1.1/04-generator-additional-red.log), [GREEN](evidence-v0.1.1/05-generator-green.log) |
Python 계약은 fake provider/작은 PCM fixture로 실패를 강제한다. 원자 디렉터리 교체와
FFmpeg MP3 변환은 테스트에서도 실제 실행한다. 이 fixture는 public 음성에 사용하지
않았다. 실제 provider의 101개 생성은 다음 별도 로그에 있으며 실패/재시도는 0회였다.
전체 `npm test`는 Python 계약 runner도 포함하며 **skip 없이** 통과했다.
## 실제 음성 생성·전수 독립 검사
명령: `npm run audio:generate`.
생성 완료: **2026-10-14T06:55:41.751382+00:00**.
[101개 실제 생성 로그](evidence-v0.1.1/06-audio-generate.log).
| 항목 | 실제 결과 |
| --- | --- |
| WAV 개수 | 101개, 101개 해시 모두 고유하고 v0.1의 같은 파일과 모두 다름 |
| WAV 합계 | **34,898,524바이트** (약 33.282MiB), 48MiB 예산 이내 |
| PCM | 전부 **24,000Hz · mono · signed 16-bit PCM** |
| duration | **3.816–11.256초**, 안내 7.056초 |
| RMS 범위 | **0.0999998534–0.1000000486** |
| peak 범위 | **0.3692016602–0.6843261719**, full-scale 0개 |
| 원문·bytes·duration·SHA-256 | 101/101 일치 |
| FFprobe 포맷 확인 + FFmpeg 전체 디코드 | 101/101 성공 |
| Chrome 실제 WAV 디코드·해시·레벨 검사 | 101/101 성공, 외부 페이지 요청 0·JS 예외 0 |
| 남은 임시 MP3/공개 staging 폴더 | 0개 |
[독립 검사 스크립트](evidence-v0.1.1/verify_audio.py)는 생성기의 검증 함수를
import하지 않는다. Python wave·해시·앱 원문과 FFprobe/FFmpeg를 별도로 대조한다.
[원문 로그](evidence-v0.1.1/12-independent-audio.log),
[파일별 수치 JSON](evidence-v0.1.1/audio-integrity.json).
[Chrome 전수 검사 스크립트](evidence-v0.1.1/verify_browser.mjs)는 production preview의
WAV를 실제 `OfflineAudioContext`로 디코드한다. 응답 bytes/hash, 채널, rate, duration,
RMS, peak와 UI/index 버전을 검사한다.
[Chrome 로그](evidence-v0.1.1/15-browser-audio.log),
[101개 디코드 결과 및 sandbox 상태](evidence-v0.1.1/browser-audio-integrity.json).
청취용: [intro.wav](../public/audio/intro.wav), [luck-apple.wav](../public/audio/luck-apple.wav).
## 최종 검증
환경: Node **26.7.0**, npm **11.19.0**, Python **3.11.16**, Chrome **146.0.7680.80**,
Linux 6.8.0, glibc 2.39. [실측 환경과 pip check](evidence-v0.1.1/18-environment.log).
| 검증 | 결과 | evidence |
| --- | --- | --- |
| `npm ci` | PASS, 238 packages 설치 | [로그](evidence-v0.1.1/00-npm-ci.log) |
| `npm run lint` | PASS, ESLint + TypeScript strict | [최종 로그](evidence-v0.1.1/16-final-lint.log) |
| `npm test` | **11 files / 60 passed**, skip 0; Python 18개 계약 포함 | [로그](evidence-v0.1.1/11-full-test.log) |
| `npm run audio:generate` | **101개 신규 생성·검증·원자 교체 성공** | [로그](evidence-v0.1.1/06-audio-generate.log) |
| `npm run build` | PASS, 101개 해시·런타임 MIT notice 전문 검증 | [로그](evidence-v0.1.1/13-build.log) |
| sandboxed system Chrome desktop/mobile suite | **12 passed (2.3m)**, skip 0 | [로그](evidence-v0.1.1/14-browser.log) |
| sandboxed Chrome 101개 전수 디코드 | PASS, Namespace/PID/Network/Seccomp sandbox 활성 | [로그](evidence-v0.1.1/15-browser-audio.log) |
| `npm audit --audit-level=high` | **0 vulnerabilities**, npm 개발 의존성 포함 | [로그](evidence-v0.1.1/10-audit.log) |
| 독립 101개 원문/hash/PCM/FFmpeg 검사 | PASS | [JSON](evidence-v0.1.1/audio-integrity.json) |
| 소스·문서·manifest 비밀값 패턴 검사 | 40개 텍스트 파일, 0 matches | [기록](evidence-v0.1.1/17-security-history.json) |
| `git diff --check`·문서 링크·sandbox 실행 인자·HEAD·역사 기록 최종 검사 | PASS | [최종 무결성](evidence-v0.1.1/19-final-integrity.json) |
| 과거 evidence + RESULT 해시 대조 | **115개 전부 동일** | [baseline](evidence-v0.1.1/baseline.json), [검사](evidence-v0.1.1/17-security-history.json) |
브라우저 전체 명령:
`env -u PLAYWRIGHT_NO_SANDBOX CHROME_PATH=/usr/bin/google-chrome DEBUG=pw:browser npm run test:browser`.
두 viewport(1280×1000, 360×800)에서 실제 음성으로 10문제 완주·재청취·404 재시도·
키보드·레이아웃·reduced motion·axe·크레딧·MIT HTTP 응답이 모두 통과했다.
시작·게임·결과 axe 위반 0, 외부 페이지 요청 0, 페이지 JS 예외 0이다.
로컬 preview만 테스트 중 열었으며 서버 배포는 하지 않았다.
Chrome 전수 검사에서는 `chrome://sandbox`의 Namespace·Seccomp 상태도 실제 확인했다.
headless 브라우저는 실제 파일을 디코드하고 Web Audio를 실행하지만 물리적 스피커
청취를 대신하지 않는다. Chrome stderr의 시스템 GPU/GCM 진단과 페이지 JS 예외는 구분한다.
스크린샷: [desktop 시작](evidence-v0.1.1/desktop-home.png),
[게임](evidence-v0.1.1/desktop-game.png), [결과](evidence-v0.1.1/desktop-results.png),
[mobile 시작](evidence-v0.1.1/mobile-home.png), [게임](evidence-v0.1.1/mobile-game.png),
[결과](evidence-v0.1.1/mobile-results.png).
## 변경 파일과 기록 보존
- 앱 표기: `src/App.tsx`, `index.html`, `package.json`, `package-lock.json`.
- 생성: `scripts/generate_audio.py`, 신규 `scripts/neural_audio.py`,
`requirements-audio.txt`, `.gitignore`, `eslint.config.js`의 venv 제외.
- 자산: `public/audio/*.wav` 101개와 `manifest.json`.
- 계약 테스트: `tests/assets.test.ts`, `tests/App.test.tsx`, 신규
`tests/neural-release.test.ts`, `tests/generator.test.ts`, `tests/python/test_neural_audio.py`.
- 기존 browser tests는 새 스크린샷 경로와 v0.1.1 실측 길이 주석만 변경했다.
`tests/browser/game.spec.ts`, `tests/browser/ui.spec.ts`. 기존 assertion/timeout은 유지했다.
- 문서: `README.md`, `LICENSE`, `docs/AUDIO_PROVENANCE.md`,
`docs/ARCHITECTURE.md`, `docs/DEPLOYMENT.md`.
- 이번 기록: `.agent/RESULT-v0.1.1.md`, `.agent/evidence-v0.1.1/`.
이전 `.agent/RESULT.md`, `.agent/evidence/`의 파일은 수정하지 않았다.
스크린샷도 새 경로에만 저장한다. 입력 TASK/ACCEPTANCE의 시작 상태는 untracked였으며
Codex가 새로 작성한 입력 문서가 아니다. 전체 파일 목록은
[changed-files.txt](evidence-v0.1.1/changed-files.txt)에 별도로 남긴다.
## 남은 청감·provider 한계
- 자동 검사와 실제 브라우저 재생은 완료했지만 **사람의 청감 평가를 수행한 것은 아니다**.
한국어 발음·유사 자모 구분·웃음·소음 혼합 난이도는 대표 샘플과 게임으로 직접 평가해야 한다.
- 원격 모델/서비스는 고정할 수 없다. pinned client로 절차를 재현해도 다음 생성의
바이트가 같다는 보장은 없다. provider 장애·제한·음성 목록 변경 시 명확히 실패한다.
- edge-tts의 LGPLv3(일부 MIT)와 FFmpeg의 빌드별 LGPL/GPL은 provider 서비스 조건 및
음성 출력의 권리와 별개다. 생성 음성의 독점 권리나 포괄적 상업 이용 허락을 주장하지 않는다.
근거 링크·확인일·조건의 한계는 [AUDIO_PROVENANCE](../docs/AUDIO_PROVENANCE.md)에 기록했다.
- 원자 교체는 Linux와 해당 파일시스템의 지원이 필요하다. SIGKILL/전원 손실 때 임시
숨김 폴더는 남을 수 있고 전원 손실 내구성까지 보장하지 않는다. 일반 실패·Ctrl-C는 정리한다.
- 실제 모바일 Safari/물리적 오디오 장치 청취는 이번 Chrome 검증 범위 밖이다.
## 2026-10-14 추가 — 배포 후 오디오 캐시 회귀 수정
제품 버전 **0.1.1**을 유지하면서 intro와 목표 100개 WAV 모두
`?v=0.1.1`을 붙이도록 수정했다. `src/audio/assets.ts`의
`AUDIO_ASSET_VERSION`과 `audioAssetUrl`을 출제·오디오 엔진이 함께 사용한다.
WAV/manifest 및 package/lock은 변경하지 않았다.
발견 원인은 **음성 내용 교체 후에도 요청 URL이 같았던 것**이다. 사용자 보고의
배포 Nginx `/audio` 7일 캐시에서 기존 사용자는 이전 음성을 계속 받을 수 있었다.
기존 배포 문서의 재검증 가정과 실제 설정이 달랐으며, 브라우저 테스트의
전체 URL `.endsWith('.wav')`와 404 glob도 query string을 놓쳤다.
원격 서버에는 접속하지 않고 소스·로컬 production build에서 재현했다.
앱 구현을 수정하기 전에 unit/browser 계약을 작성하고 실제 RED를 확인했다.
RED 때 앱 소스가 그대로였다는 기록은 [04-red-state.json](evidence-v0.1.1/cache-regression/04-red-state.json)에 있다.
| 계약/검증 | 결과 | 새 evidence |
| --- | --- | --- |
| 목표 100개 버전·intro/target fetch·각각 404 retry·query pathname 판정 | RED 5 failed / 12 passed → GREEN 17 passed | [RED](evidence-v0.1.1/cache-regression/01-unit-red.log), [GREEN](evidence-v0.1.1/cache-regression/05-unit-green.log) |
| 실제 브라우저 요청/정답 mapping·intro/target 404·101개 URL | 구현 전 desktop RED 4 failed → 전체 desktop/mobile GREEN 16 passed (2.6m) | [RED](evidence-v0.1.1/cache-regression/03-browser-red.log), [GREEN](evidence-v0.1.1/cache-regression/09-browser-green.log) |
| `npm run lint` | PASS | [로그](evidence-v0.1.1/cache-regression/06-lint.log) |
| `npm test` | 12 files / 65 passed, skip 0; Python 18개 계약 포함 | [로그](evidence-v0.1.1/cache-regression/07-full-test.log) |
| `npm run build` | PASS, 101개 WAV·notice 검증 | [로그](evidence-v0.1.1/cache-regression/08-build.log) |
| 실제 Chrome sandbox | Namespace·PID·Network·Seccomp-BPF 활성, `--no-sandbox` 없음 | [로그](evidence-v0.1.1/cache-regression/11-sandbox-green.log) |
| query URL 전수 Chrome 해시·bytes·24kHz mono 디코드·duration·RMS·peak | 두 viewport 각각 101/101, 외부 요청 0·JS 예외 0 | [desktop](evidence-v0.1.1/cache-regression/artifacts/desktop-browser-audio-integrity.json), [mobile](evidence-v0.1.1/cache-regression/artifacts/mobile-browser-audio-integrity.json) |
| 과거 evidence·자산·제품 버전 파일 보존 및 HEAD·diff 검사 | 254개 해시 동일, 과거 evidence 149개 포함 | [최종 무결성](evidence-v0.1.1/cache-regression/13-final-integrity.json) |
전체 브라우저 명령은
`env -u PLAYWRIGHT_NO_SANDBOX CHROME_PATH=/usr/bin/google-chrome DEBUG=pw:browser npm run test:browser`이다.
실제 재생·재청취·10문제 완주·404 복구 후 정답·접근성 검증을 유지했다.
101개 query URL 검사를 `tests/browser/audio.spec.ts`로 정규 suite에 편입했고,
URL 판정 helper의 query 순서·가짜 WAV 접미사도 단위 테스트로 고정했다.
런타임 외부 요청이나 manifest 조회는 추가하지 않았다.
브라우저 스크린샷은 이제 `test-results/`를 사용하며 이번 결과는
[새 artifacts 경로](evidence-v0.1.1/cache-regression/artifacts/)에 복사했다.
과거 evidence와 기존 이 보고서 본문은 보존하고 이번 기록만 추가했다.
보조 sandbox probe의 최초 라벨 판정 오류와 수정 결과도
[원인·RED/GREEN·최종 결과 로그](evidence-v0.1.1/cache-regression/12-cache-regression-result.log)에 기록했다.
README·ARCHITECTURE·DEPLOYMENT에 자산 버전 갱신 규칙과 7일 캐시 예시를 반영했다.
이 변경의 검증 대상은 로컬 build이며 **Git commit/push/tag/merge와 서버 배포는 실행하지 않았다.**
+59
View File
@@ -0,0 +1,59 @@
# TASK — Find-Word v0.1.1 Korean neural voice upgrade
## 사용자 지시
현재 v0.1의 한국어 음성이 제대로 만들어지지 않았다. 음성 품질을 높이고 샘플을 다시 생성하며 버전을 0.1.1로 올린다. 모든 소스는 Gitea에 push 및 main merge할 예정이다. Codex는 구현만 하고 commit/push/deploy는 하지 않는다.
## 고정 계약
- 정확한 크레딧: `Designed by OZ at Heat-T Medical Inc.`
- canonical repository: `https://source.ibit.kr/OZ-Group/Find-Word`
- 작업 브랜치: `fix/v0.1.1-neural-voice`
- 버전: UI/package/docs/manifest 모두 `0.1.1`
- 한국어 상세 소스 주석 유지
- 기존 10개 mechanic, 100개 문장 조합, 8개 환경, 5단계 SNR, 객관식·주관식 기능 보존
## 선택한 생성 방식
- 직접 생성한 사전 샘플에서 사용 가능한 고품질 음성: `ko-KR-HyunsuMultilingualNeural`
- 생성 클라이언트: `edge-tts==7.3.1`
- 권장 prosody: rate `-6%`, pitch `-4Hz`
- 앱 런타임에는 외부 TTS/API 요청이 없어야 한다.
- 생성 시 임시 MP3를 받아 ffmpeg로 24kHz mono PCM s16 WAV로 변환한다.
- 음성 간 레벨 편차와 peak를 완화하되 발음을 훼손하는 과도한 DSP를 하지 않는다.
- 네트워크·provider 오류에 bounded retry와 명확한 실패를 제공한다.
- 부분 실패가 기존 public/audio를 훼손하지 않도록 임시 디렉터리에서 전체 생성·검증 후 원자 교체한다.
- API 키·쿠키·인증정보를 저장하지 않는다.
## 품질·재현성 요구사항
- intro 1개 + 목표 문장 100개, 총 101개를 모두 새로 생성한다.
- manifest에 version, provider, voice, rate, pitch, edge-tts version, ffmpeg version, sample rate, SHA-256, bytes, duration, 원문을 기록한다.
- 24kHz mono 16-bit PCM, 비무음, peak full-scale 미도달, 비정상적으로 짧거나 긴 파일 없음.
- `audio:generate`는 pinned venv의 Python으로 재현 가능해야 하고 README/AUDIO_PROVENANCE에 설치·생성 절차와 provider 의존성·한계를 기록한다.
- `public/audio/intro.wav`와 대표 샘플 `luck-apple.wav`가 청취용 샘플이다.
- eSpeak cache/download 경로·문서·manifest 의존성을 제거한다. 과거 evidence는 당시 기록이므로 내용 변조 없이 보존한다.
- 생성 도구의 오픈소스 라이선스와 서비스 사용 조건을 과장 없이 문서화한다. 프로젝트가 음성 자체에 독점 권리를 주장한다고 쓰지 않는다.
## TDD
1. 버전 0.1.1 계약 테스트 RED
2. neural provider/voice/manifest 계약 RED
3. 24kHz·비무음·peak·duration·101개 integrity RED
4. generator atomicity/retry/unsafe secret absence 테스트 RED
5. 기존 full suite와 browser suite GREEN
## 최종 검증
- npm ci
- npm run lint
- npm test
- npm run audio:generate 또는 명시적 생성 명령
- npm run build
- sandboxed system Chrome browser tests
- npm audit --audit-level=high
- 101개 manifest/hash/PCM 독립 검사
## 기록
`.agent/RESULT-v0.1.1.md`에 RED/GREEN, 변경 파일, 생성 provider/voice, 자산 크기, 최종 결과, 남은 청감·provider 위험을 기록한다.
+44
View File
@@ -0,0 +1,44 @@
Collecting edge-tts==7.3.1
Using cached edge_tts-7.3.1-py3-none-any.whl.metadata (6.1 kB)
Collecting aiohttp<4.0.0,>=3.8.0 (from edge-tts==7.3.1)
Using cached aiohttp-3.14.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (8.3 kB)
Collecting certifi>=2023.11.17 (from edge-tts==7.3.1)
Using cached certifi-2026.7.22-py3-none-any.whl.metadata (2.5 kB)
Collecting tabulate<1.0.0,>=0.4.4 (from edge-tts==7.3.1)
Using cached tabulate-0.10.0-py3-none-any.whl.metadata (40 kB)
Collecting typing-extensions<5.0.0,>=4.1.0 (from edge-tts==7.3.1)
Using cached typing_extensions-4.16.0-py3-none-any.whl.metadata (3.3 kB)
Collecting aiohappyeyeballs>=2.5.0 (from aiohttp<4.0.0,>=3.8.0->edge-tts==7.3.1)
Using cached aiohappyeyeballs-2.7.1-py3-none-any.whl.metadata (5.9 kB)
Collecting aiosignal>=1.4.0 (from aiohttp<4.0.0,>=3.8.0->edge-tts==7.3.1)
Using cached aiosignal-1.4.0-py3-none-any.whl.metadata (3.7 kB)
Collecting attrs>=17.3.0 (from aiohttp<4.0.0,>=3.8.0->edge-tts==7.3.1)
Using cached attrs-26.1.0-py3-none-any.whl.metadata (8.8 kB)
Collecting frozenlist>=1.1.1 (from aiohttp<4.0.0,>=3.8.0->edge-tts==7.3.1)
Using cached frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.metadata (20 kB)
Collecting multidict<8.0,>=4.5 (from aiohttp<4.0.0,>=3.8.0->edge-tts==7.3.1)
Using cached multidict-7.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (6.2 kB)
Collecting propcache>=0.2.0 (from aiohttp<4.0.0,>=3.8.0->edge-tts==7.3.1)
Using cached propcache-0.5.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (25 kB)
Collecting yarl<2.0,>=1.25.1 (from aiohttp<4.0.0,>=3.8.0->edge-tts==7.3.1)
Using cached yarl-1.25.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.metadata (111 kB)
Collecting idna>=2.0 (from yarl<2.0,>=1.25.1->aiohttp<4.0.0,>=3.8.0->edge-tts==7.3.1)
Using cached idna-3.20-py3-none-any.whl.metadata (7.2 kB)
Using cached edge_tts-7.3.1-py3-none-any.whl (38 kB)
Using cached aiohttp-3.14.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.9 MB)
Using cached certifi-2026.7.22-py3-none-any.whl (136 kB)
Using cached tabulate-0.10.0-py3-none-any.whl (39 kB)
Using cached typing_extensions-4.16.0-py3-none-any.whl (45 kB)
Using cached aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (231 kB)
Using cached multidict-7.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (480 kB)
Using cached propcache-0.5.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (235 kB)
Using cached yarl-1.25.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (117 kB)
Using cached idna-3.20-py3-none-any.whl (69 kB)
Installing collected packages: typing-extensions, tabulate, propcache, multidict, idna, frozenlist, certifi, attrs, aiohappyeyeballs, yarl, aiosignal, aiohttp, edge-tts
Successfully installed aiohappyeyeballs-2.7.1 aiohttp-3.14.5 aiosignal-1.4.0 attrs-26.1.0 certifi-2026.7.22 edge-tts-7.3.1 frozenlist-1.8.0 idna-3.20 multidict-7.1.0 propcache-0.5.4 tabulate-0.10.0 typing-extensions-4.16.0 yarl-1.25.1
[notice] A new release of pip is available: 24.0 -> 26.2.1
[notice] To update, run: python -m pip install --upgrade pip
+7
View File
@@ -0,0 +1,7 @@
added 238 packages, and audited 239 packages in 3s
56 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+305
View File
@@ -0,0 +1,305 @@
test_all_101_are_validated_before_single_atomic_publication (test_neural_audio.GeneratorContract.test_all_101_are_validated_before_single_atomic_publication) ... ERROR
test_atomic_exchange_keeps_old_tree_at_staging_path (test_neural_audio.GeneratorContract.test_atomic_exchange_keeps_old_tree_at_staging_path) ... ERROR
test_atomic_first_publication (test_neural_audio.GeneratorContract.test_atomic_first_publication) ... ERROR
test_cli_import_has_no_generation_or_filesystem_side_effects (test_neural_audio.GeneratorContract.test_cli_import_has_no_generation_or_filesystem_side_effects) ... FAIL
test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell (test_neural_audio.GeneratorContract.test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell) ... ERROR
test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets (test_neural_audio.GeneratorContract.test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets) ... FAIL
test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24 (test_neural_audio.GeneratorContract.test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24) ... ERROR
test_ffmpeg_failure_is_not_retried_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_ffmpeg_failure_is_not_retried_and_preserves_existing_files) ... FAIL
test_interruption_preserves_existing_files_and_cleans_temporary_data (test_neural_audio.GeneratorContract.test_interruption_preserves_existing_files_and_cleans_temporary_data) ... ERROR
test_invalid_pcm_never_reaches_publication (test_neural_audio.GeneratorContract.test_invalid_pcm_never_reaches_publication) ... ERROR
test_publication_failure_preserves_existing_files (test_neural_audio.GeneratorContract.test_publication_failure_preserves_existing_files) ... ERROR
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) ...
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': 'intro.wav', 'text': '안내 문장'}) ... ERROR
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': 'intro.wav', 'text': '안내 문장'}) ... ERROR
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': '../escape.wav', 'text': '외부'}) ... ERROR
test_timeout_is_bounded_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_timeout_is_bounded_and_preserves_existing_files) ... FAIL
test_transient_provider_failures_retry_cleanly_with_bounded_backoff (test_neural_audio.GeneratorContract.test_transient_provider_failures_retry_cleanly_with_bounded_backoff) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) ...
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'amplitude': 0}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'amplitude': 32767}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'rate': 16000}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'channels': 2}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'width': 1}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'duration': 0.2}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'duration': 21}) ... ERROR
test_valid_pcm_returns_measured_hash_bytes_duration_and_levels (test_neural_audio.PCMContract.test_valid_pcm_returns_measured_hash_bytes_duration_and_levels) ... ERROR
======================================================================
ERROR: test_all_101_are_validated_before_single_atomic_publication (test_neural_audio.GeneratorContract.test_all_101_are_validated_before_single_atomic_publication)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 78, in test_all_101_are_validated_before_single_atomic_publication
result = self.run_generate()
^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_atomic_exchange_keeps_old_tree_at_staging_path (test_neural_audio.GeneratorContract.test_atomic_exchange_keeps_old_tree_at_staging_path)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 202, in test_atomic_exchange_keeps_old_tree_at_staging_path
audio.atomic_publish(staged, self.output)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 13, in atomic_publish
raise NotImplementedError("원자 디렉터리 교체 미구현")
NotImplementedError: 원자 디렉터리 교체 미구현
======================================================================
ERROR: test_atomic_first_publication (test_neural_audio.GeneratorContract.test_atomic_first_publication)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 211, in test_atomic_first_publication
audio.atomic_publish(staged, output)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 13, in atomic_publish
raise NotImplementedError("원자 디렉터리 교체 미구현")
NotImplementedError: 원자 디렉터리 교체 미구현
======================================================================
ERROR: test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell (test_neural_audio.GeneratorContract.test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 177, in test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell
audio.synthesize_edge("한국어 ; $(literal)", path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 17, in synthesize_edge
raise NotImplementedError("pinned edge-tts 실행 미구현")
NotImplementedError: pinned edge-tts 실행 미구현
======================================================================
ERROR: test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24 (test_neural_audio.GeneratorContract.test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 190, in test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24
audio.convert_mp3(mp3, output)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 21, in convert_mp3
raise NotImplementedError("ffmpeg 변환 및 선형 레벨 보정 미구현")
NotImplementedError: ffmpeg 변환 및 선형 레벨 보정 미구현
======================================================================
ERROR: test_interruption_preserves_existing_files_and_cleans_temporary_data (test_neural_audio.GeneratorContract.test_interruption_preserves_existing_files_and_cleans_temporary_data)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 149, in test_interruption_preserves_existing_files_and_cleans_temporary_data
self.run_generate(synthesize=interrupt)
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_invalid_pcm_never_reaches_publication (test_neural_audio.GeneratorContract.test_invalid_pcm_never_reaches_publication)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 132, in test_invalid_pcm_never_reaches_publication
self.run_generate(convert=invalid)
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_publication_failure_preserves_existing_files (test_neural_audio.GeneratorContract.test_publication_failure_preserves_existing_files)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 155, in test_publication_failure_preserves_existing_files
self.run_generate()
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': 'intro.wav', 'text': '안내 문장'})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 163, in test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests
audio.generate(entries, self.output, synthesize=self.synthesize)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': 'intro.wav', 'text': '안내 문장'})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 163, in test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests
audio.generate(entries, self.output, synthesize=self.synthesize)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': '../escape.wav', 'text': '외부'})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 163, in test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests
audio.generate(entries, self.output, synthesize=self.synthesize)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_transient_provider_failures_retry_cleanly_with_bounded_backoff (test_neural_audio.GeneratorContract.test_transient_provider_failures_retry_cleanly_with_bounded_backoff)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 97, in test_transient_provider_failures_retry_cleanly_with_bounded_backoff
self.run_generate(synthesize=flaky)
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'amplitude': 0})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 225, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'amplitude': 32767})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 225, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'rate': 16000})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 225, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'channels': 2})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 225, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'width': 1})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 225, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'duration': 0.2})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 225, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'duration': 21})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 225, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_valid_pcm_returns_measured_hash_bytes_duration_and_levels (test_neural_audio.PCMContract.test_valid_pcm_returns_measured_hash_bytes_duration_and_levels)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 231, in test_valid_pcm_returns_measured_hash_bytes_duration_and_levels
result = audio.inspect_wav(path)
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
FAIL: test_cli_import_has_no_generation_or_filesystem_side_effects (test_neural_audio.GeneratorContract.test_cli_import_has_no_generation_or_filesystem_side_effects)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 172, in test_cli_import_has_no_generation_or_filesystem_side_effects
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/generate_audio.py", line 27, in <module>
source = subprocess.check_output([
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/.local/share/uv/python/cpython-3.11.16-linux-x86_64-gnu/lib/python3.11/unittest/mock.py", line 1124, in __call__
return self._mock_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/.local/share/uv/python/cpython-3.11.16-linux-x86_64-gnu/lib/python3.11/unittest/mock.py", line 1128, in _mock_call
return self._execute_mock_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/.local/share/uv/python/cpython-3.11.16-linux-x86_64-gnu/lib/python3.11/unittest/mock.py", line 1183, in _execute_mock_call
raise effect
AssertionError: import 실행 금지
======================================================================
FAIL: test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets (test_neural_audio.GeneratorContract.test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets)
----------------------------------------------------------------------
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 111, in test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets
with self.assertRaisesRegex(RuntimeError, "target-1.wav.*3") as failure:
AssertionError: "target-1.wav.*3" does not match "neural 생성·retry·검증·원자 교체 미구현"
======================================================================
FAIL: test_ffmpeg_failure_is_not_retried_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_ffmpeg_failure_is_not_retried_and_preserves_existing_files)
----------------------------------------------------------------------
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 138, in test_ffmpeg_failure_is_not_retried_and_preserves_existing_files
with self.assertRaisesRegex(RuntimeError, "intro.wav.*변환"):
AssertionError: "intro.wav.*변환" does not match "neural 생성·retry·검증·원자 교체 미구현"
======================================================================
FAIL: test_timeout_is_bounded_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_timeout_is_bounded_and_preserves_existing_files)
----------------------------------------------------------------------
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 123, in test_timeout_is_bounded_and_preserves_existing_files
with self.assertRaisesRegex(RuntimeError, "intro.wav.*3"):
AssertionError: "intro.wav.*3" does not match "neural 생성·retry·검증·원자 교체 미구현"
----------------------------------------------------------------------
Ran 16 tests in 0.633s
FAILED (failures=4, errors=20)
@@ -0,0 +1,332 @@
test_all_101_are_validated_before_single_atomic_publication (test_neural_audio.GeneratorContract.test_all_101_are_validated_before_single_atomic_publication) ... ERROR
test_atomic_exchange_keeps_old_tree_at_staging_path (test_neural_audio.GeneratorContract.test_atomic_exchange_keeps_old_tree_at_staging_path) ... ERROR
test_atomic_first_publication (test_neural_audio.GeneratorContract.test_atomic_first_publication) ... ERROR
test_cli_import_has_no_generation_or_filesystem_side_effects (test_neural_audio.GeneratorContract.test_cli_import_has_no_generation_or_filesystem_side_effects) ... FAIL
test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell (test_neural_audio.GeneratorContract.test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell) ... ERROR
test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets (test_neural_audio.GeneratorContract.test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets) ... FAIL
test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24 (test_neural_audio.GeneratorContract.test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24) ... ERROR
test_ffmpeg_failure_is_not_retried_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_ffmpeg_failure_is_not_retried_and_preserves_existing_files) ... FAIL
test_full_validation_detects_changed_earlier_file_before_publication (test_neural_audio.GeneratorContract.test_full_validation_detects_changed_earlier_file_before_publication) ... ERROR
test_interruption_preserves_existing_files_and_cleans_temporary_data (test_neural_audio.GeneratorContract.test_interruption_preserves_existing_files_and_cleans_temporary_data) ... ERROR
test_invalid_pcm_never_reaches_publication (test_neural_audio.GeneratorContract.test_invalid_pcm_never_reaches_publication) ... ERROR
test_publication_failure_preserves_existing_files (test_neural_audio.GeneratorContract.test_publication_failure_preserves_existing_files) ... ERROR
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) ...
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': 'intro.wav', 'text': '안내 문장'}) ... ERROR
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': 'intro.wav', 'text': '안내 문장'}) ... ERROR
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': '../escape.wav', 'text': '외부'}) ... ERROR
test_timeout_is_bounded_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_timeout_is_bounded_and_preserves_existing_files) ... FAIL
test_transient_provider_failures_retry_cleanly_with_bounded_backoff (test_neural_audio.GeneratorContract.test_transient_provider_failures_retry_cleanly_with_bounded_backoff) ... ERROR
test_wrong_edge_version_fails_before_network_or_asset_changes (test_neural_audio.GeneratorContract.test_wrong_edge_version_fails_before_network_or_asset_changes) ... FAIL
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) ...
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'amplitude': 0}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'amplitude': 32767}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'rate': 16000}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'channels': 2}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'width': 1}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'duration': 0.2}) ... ERROR
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'duration': 21}) ... ERROR
test_valid_pcm_returns_measured_hash_bytes_duration_and_levels (test_neural_audio.PCMContract.test_valid_pcm_returns_measured_hash_bytes_duration_and_levels) ... ERROR
======================================================================
ERROR: test_all_101_are_validated_before_single_atomic_publication (test_neural_audio.GeneratorContract.test_all_101_are_validated_before_single_atomic_publication)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 78, in test_all_101_are_validated_before_single_atomic_publication
result = self.run_generate()
^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_atomic_exchange_keeps_old_tree_at_staging_path (test_neural_audio.GeneratorContract.test_atomic_exchange_keeps_old_tree_at_staging_path)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 218, in test_atomic_exchange_keeps_old_tree_at_staging_path
audio.atomic_publish(staged, self.output)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 13, in atomic_publish
raise NotImplementedError("원자 디렉터리 교체 미구현")
NotImplementedError: 원자 디렉터리 교체 미구현
======================================================================
ERROR: test_atomic_first_publication (test_neural_audio.GeneratorContract.test_atomic_first_publication)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 227, in test_atomic_first_publication
audio.atomic_publish(staged, output)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 13, in atomic_publish
raise NotImplementedError("원자 디렉터리 교체 미구현")
NotImplementedError: 원자 디렉터리 교체 미구현
======================================================================
ERROR: test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell (test_neural_audio.GeneratorContract.test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 193, in test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell
audio.synthesize_edge("한국어 ; $(literal)", path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 17, in synthesize_edge
raise NotImplementedError("pinned edge-tts 실행 미구현")
NotImplementedError: pinned edge-tts 실행 미구현
======================================================================
ERROR: test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24 (test_neural_audio.GeneratorContract.test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 206, in test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24
audio.convert_mp3(mp3, output)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 21, in convert_mp3
raise NotImplementedError("ffmpeg 변환 및 선형 레벨 보정 미구현")
NotImplementedError: ffmpeg 변환 및 선형 레벨 보정 미구현
======================================================================
ERROR: test_full_validation_detects_changed_earlier_file_before_publication (test_neural_audio.GeneratorContract.test_full_validation_detects_changed_earlier_file_before_publication)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 164, in test_full_validation_detects_changed_earlier_file_before_publication
self.run_generate(convert=tamper)
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_interruption_preserves_existing_files_and_cleans_temporary_data (test_neural_audio.GeneratorContract.test_interruption_preserves_existing_files_and_cleans_temporary_data)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 149, in test_interruption_preserves_existing_files_and_cleans_temporary_data
self.run_generate(synthesize=interrupt)
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_invalid_pcm_never_reaches_publication (test_neural_audio.GeneratorContract.test_invalid_pcm_never_reaches_publication)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 132, in test_invalid_pcm_never_reaches_publication
self.run_generate(convert=invalid)
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_publication_failure_preserves_existing_files (test_neural_audio.GeneratorContract.test_publication_failure_preserves_existing_files)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 155, in test_publication_failure_preserves_existing_files
self.run_generate()
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': 'intro.wav', 'text': '안내 문장'})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 179, in test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests
audio.generate(entries, self.output, synthesize=self.synthesize)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': 'intro.wav', 'text': '안내 문장'})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 179, in test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests
audio.generate(entries, self.output, synthesize=self.synthesize)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) (entries={'file': '../escape.wav', 'text': '외부'})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 179, in test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests
audio.generate(entries, self.output, synthesize=self.synthesize)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_transient_provider_failures_retry_cleanly_with_bounded_backoff (test_neural_audio.GeneratorContract.test_transient_provider_failures_retry_cleanly_with_bounded_backoff)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 97, in test_transient_provider_failures_retry_cleanly_with_bounded_backoff
self.run_generate(synthesize=flaky)
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 69, in run_generate
return audio.generate(ENTRIES, self.output, synthesize=synthesize or self.synthesize,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 5, in generate
raise NotImplementedError("neural 생성·retry·검증·원자 교체 미구현")
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'amplitude': 0})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 241, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'amplitude': 32767})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 241, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'rate': 16000})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 241, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'channels': 2})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 241, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'width': 1})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 241, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'duration': 0.2})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 241, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) (options={'duration': 21})
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 241, in test_rejects_silence_clipping_bad_format_and_abnormal_duration
audio.inspect_wav(path)
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
ERROR: test_valid_pcm_returns_measured_hash_bytes_duration_and_levels (test_neural_audio.PCMContract.test_valid_pcm_returns_measured_hash_bytes_duration_and_levels)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 247, in test_valid_pcm_returns_measured_hash_bytes_duration_and_levels
result = audio.inspect_wav(path)
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/neural_audio.py", line 9, in inspect_wav
raise NotImplementedError("PCM 품질 검사 미구현")
NotImplementedError: PCM 품질 검사 미구현
======================================================================
FAIL: test_cli_import_has_no_generation_or_filesystem_side_effects (test_neural_audio.GeneratorContract.test_cli_import_has_no_generation_or_filesystem_side_effects)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 188, in test_cli_import_has_no_generation_or_filesystem_side_effects
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 940, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/home/hermes/worktrees/find-word-v0.1.1/scripts/generate_audio.py", line 27, in <module>
source = subprocess.check_output([
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/.local/share/uv/python/cpython-3.11.16-linux-x86_64-gnu/lib/python3.11/unittest/mock.py", line 1124, in __call__
return self._mock_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/.local/share/uv/python/cpython-3.11.16-linux-x86_64-gnu/lib/python3.11/unittest/mock.py", line 1128, in _mock_call
return self._execute_mock_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/hermes/.local/share/uv/python/cpython-3.11.16-linux-x86_64-gnu/lib/python3.11/unittest/mock.py", line 1183, in _execute_mock_call
raise effect
AssertionError: import 실행 금지
======================================================================
FAIL: test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets (test_neural_audio.GeneratorContract.test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets)
----------------------------------------------------------------------
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 111, in test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets
with self.assertRaisesRegex(RuntimeError, "target-1.wav.*3") as failure:
AssertionError: "target-1.wav.*3" does not match "neural 생성·retry·검증·원자 교체 미구현"
======================================================================
FAIL: test_ffmpeg_failure_is_not_retried_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_ffmpeg_failure_is_not_retried_and_preserves_existing_files)
----------------------------------------------------------------------
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 138, in test_ffmpeg_failure_is_not_retried_and_preserves_existing_files
with self.assertRaisesRegex(RuntimeError, "intro.wav.*변환"):
AssertionError: "intro.wav.*변환" does not match "neural 생성·retry·검증·원자 교체 미구현"
======================================================================
FAIL: test_timeout_is_bounded_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_timeout_is_bounded_and_preserves_existing_files)
----------------------------------------------------------------------
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 123, in test_timeout_is_bounded_and_preserves_existing_files
with self.assertRaisesRegex(RuntimeError, "intro.wav.*3"):
AssertionError: "intro.wav.*3" does not match "neural 생성·retry·검증·원자 교체 미구현"
======================================================================
FAIL: test_wrong_edge_version_fails_before_network_or_asset_changes (test_neural_audio.GeneratorContract.test_wrong_edge_version_fails_before_network_or_asset_changes)
----------------------------------------------------------------------
NotImplementedError: neural 생성·retry·검증·원자 교체 미구현
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/hermes/worktrees/find-word-v0.1.1/tests/python/test_neural_audio.py", line 169, in test_wrong_edge_version_fails_before_network_or_asset_changes
with self.assertRaisesRegex(RuntimeError, "7.3.1"):
AssertionError: "7.3.1" does not match "neural 생성·retry·검증·원자 교체 미구현"
----------------------------------------------------------------------
Ran 18 tests in 0.488s
FAILED (failures=5, errors=21)
@@ -0,0 +1,432 @@
test_all_101_are_validated_before_single_atomic_publication (test_neural_audio.GeneratorContract.test_all_101_are_validated_before_single_atomic_publication) ... [001/101] intro.wav 1.000s
[002/101] target-0.wav 1.000s
[003/101] target-1.wav 1.000s
[004/101] target-2.wav 1.000s
[005/101] target-3.wav 1.000s
[006/101] target-4.wav 1.000s
[007/101] target-5.wav 1.000s
[008/101] target-6.wav 1.000s
[009/101] target-7.wav 1.000s
[010/101] target-8.wav 1.000s
[011/101] target-9.wav 1.000s
[012/101] target-10.wav 1.000s
[013/101] target-11.wav 1.000s
[014/101] target-12.wav 1.000s
[015/101] target-13.wav 1.000s
[016/101] target-14.wav 1.000s
[017/101] target-15.wav 1.000s
[018/101] target-16.wav 1.000s
[019/101] target-17.wav 1.000s
[020/101] target-18.wav 1.000s
[021/101] target-19.wav 1.000s
[022/101] target-20.wav 1.000s
[023/101] target-21.wav 1.000s
[024/101] target-22.wav 1.000s
[025/101] target-23.wav 1.000s
[026/101] target-24.wav 1.000s
[027/101] target-25.wav 1.000s
[028/101] target-26.wav 1.000s
[029/101] target-27.wav 1.000s
[030/101] target-28.wav 1.000s
[031/101] target-29.wav 1.000s
[032/101] target-30.wav 1.000s
[033/101] target-31.wav 1.000s
[034/101] target-32.wav 1.000s
[035/101] target-33.wav 1.000s
[036/101] target-34.wav 1.000s
[037/101] target-35.wav 1.000s
[038/101] target-36.wav 1.000s
[039/101] target-37.wav 1.000s
[040/101] target-38.wav 1.000s
[041/101] target-39.wav 1.000s
[042/101] target-40.wav 1.000s
[043/101] target-41.wav 1.000s
[044/101] target-42.wav 1.000s
[045/101] target-43.wav 1.000s
[046/101] target-44.wav 1.000s
[047/101] target-45.wav 1.000s
[048/101] target-46.wav 1.000s
[049/101] target-47.wav 1.000s
[050/101] target-48.wav 1.000s
[051/101] target-49.wav 1.000s
[052/101] target-50.wav 1.000s
[053/101] target-51.wav 1.000s
[054/101] target-52.wav 1.000s
[055/101] target-53.wav 1.000s
[056/101] target-54.wav 1.000s
[057/101] target-55.wav 1.000s
[058/101] target-56.wav 1.000s
[059/101] target-57.wav 1.000s
[060/101] target-58.wav 1.000s
[061/101] target-59.wav 1.000s
[062/101] target-60.wav 1.000s
[063/101] target-61.wav 1.000s
[064/101] target-62.wav 1.000s
[065/101] target-63.wav 1.000s
[066/101] target-64.wav 1.000s
[067/101] target-65.wav 1.000s
[068/101] target-66.wav 1.000s
[069/101] target-67.wav 1.000s
[070/101] target-68.wav 1.000s
[071/101] target-69.wav 1.000s
[072/101] target-70.wav 1.000s
[073/101] target-71.wav 1.000s
[074/101] target-72.wav 1.000s
[075/101] target-73.wav 1.000s
[076/101] target-74.wav 1.000s
[077/101] target-75.wav 1.000s
[078/101] target-76.wav 1.000s
[079/101] target-77.wav 1.000s
[080/101] target-78.wav 1.000s
[081/101] target-79.wav 1.000s
[082/101] target-80.wav 1.000s
[083/101] target-81.wav 1.000s
[084/101] target-82.wav 1.000s
[085/101] target-83.wav 1.000s
[086/101] target-84.wav 1.000s
[087/101] target-85.wav 1.000s
[088/101] target-86.wav 1.000s
[089/101] target-87.wav 1.000s
[090/101] target-88.wav 1.000s
[091/101] target-89.wav 1.000s
[092/101] target-90.wav 1.000s
[093/101] target-91.wav 1.000s
[094/101] target-92.wav 1.000s
[095/101] target-93.wav 1.000s
[096/101] target-94.wav 1.000s
[097/101] target-95.wav 1.000s
[098/101] target-96.wav 1.000s
[099/101] target-97.wav 1.000s
[100/101] target-98.wav 1.000s
[101/101] target-99.wav 1.000s
ok
test_atomic_exchange_keeps_old_tree_at_staging_path (test_neural_audio.GeneratorContract.test_atomic_exchange_keeps_old_tree_at_staging_path) ... ok
test_atomic_first_publication (test_neural_audio.GeneratorContract.test_atomic_first_publication) ... ok
test_cli_import_has_no_generation_or_filesystem_side_effects (test_neural_audio.GeneratorContract.test_cli_import_has_no_generation_or_filesystem_side_effects) ... ok
test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell (test_neural_audio.GeneratorContract.test_edge_adapter_uses_pinned_python_prosody_timeout_and_no_shell) ... ok
test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets (test_neural_audio.GeneratorContract.test_exhausted_provider_failure_preserves_existing_files_and_redacts_secrets) ... ok
test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24 (test_neural_audio.GeneratorContract.test_ffmpeg_adapter_actually_decodes_mp3_to_normalized_pcm24) ... ok
test_ffmpeg_failure_is_not_retried_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_ffmpeg_failure_is_not_retried_and_preserves_existing_files) ... ok
test_full_validation_detects_changed_earlier_file_before_publication (test_neural_audio.GeneratorContract.test_full_validation_detects_changed_earlier_file_before_publication) ... [001/101] intro.wav 1.000s
[002/101] target-0.wav 1.000s
[003/101] target-1.wav 1.000s
[004/101] target-2.wav 1.000s
[005/101] target-3.wav 1.000s
[006/101] target-4.wav 1.000s
[007/101] target-5.wav 1.000s
[008/101] target-6.wav 1.000s
[009/101] target-7.wav 1.000s
[010/101] target-8.wav 1.000s
[011/101] target-9.wav 1.000s
[012/101] target-10.wav 1.000s
[013/101] target-11.wav 1.000s
[014/101] target-12.wav 1.000s
[015/101] target-13.wav 1.000s
[016/101] target-14.wav 1.000s
[017/101] target-15.wav 1.000s
[018/101] target-16.wav 1.000s
[019/101] target-17.wav 1.000s
[020/101] target-18.wav 1.000s
[021/101] target-19.wav 1.000s
[022/101] target-20.wav 1.000s
[023/101] target-21.wav 1.000s
[024/101] target-22.wav 1.000s
[025/101] target-23.wav 1.000s
[026/101] target-24.wav 1.000s
[027/101] target-25.wav 1.000s
[028/101] target-26.wav 1.000s
[029/101] target-27.wav 1.000s
[030/101] target-28.wav 1.000s
[031/101] target-29.wav 1.000s
[032/101] target-30.wav 1.000s
[033/101] target-31.wav 1.000s
[034/101] target-32.wav 1.000s
[035/101] target-33.wav 1.000s
[036/101] target-34.wav 1.000s
[037/101] target-35.wav 1.000s
[038/101] target-36.wav 1.000s
[039/101] target-37.wav 1.000s
[040/101] target-38.wav 1.000s
[041/101] target-39.wav 1.000s
[042/101] target-40.wav 1.000s
[043/101] target-41.wav 1.000s
[044/101] target-42.wav 1.000s
[045/101] target-43.wav 1.000s
[046/101] target-44.wav 1.000s
[047/101] target-45.wav 1.000s
[048/101] target-46.wav 1.000s
[049/101] target-47.wav 1.000s
[050/101] target-48.wav 1.000s
[051/101] target-49.wav 1.000s
[052/101] target-50.wav 1.000s
[053/101] target-51.wav 1.000s
[054/101] target-52.wav 1.000s
[055/101] target-53.wav 1.000s
[056/101] target-54.wav 1.000s
[057/101] target-55.wav 1.000s
[058/101] target-56.wav 1.000s
[059/101] target-57.wav 1.000s
[060/101] target-58.wav 1.000s
[061/101] target-59.wav 1.000s
[062/101] target-60.wav 1.000s
[063/101] target-61.wav 1.000s
[064/101] target-62.wav 1.000s
[065/101] target-63.wav 1.000s
[066/101] target-64.wav 1.000s
[067/101] target-65.wav 1.000s
[068/101] target-66.wav 1.000s
[069/101] target-67.wav 1.000s
[070/101] target-68.wav 1.000s
[071/101] target-69.wav 1.000s
[072/101] target-70.wav 1.000s
[073/101] target-71.wav 1.000s
[074/101] target-72.wav 1.000s
[075/101] target-73.wav 1.000s
[076/101] target-74.wav 1.000s
[077/101] target-75.wav 1.000s
[078/101] target-76.wav 1.000s
[079/101] target-77.wav 1.000s
[080/101] target-78.wav 1.000s
[081/101] target-79.wav 1.000s
[082/101] target-80.wav 1.000s
[083/101] target-81.wav 1.000s
[084/101] target-82.wav 1.000s
[085/101] target-83.wav 1.000s
[086/101] target-84.wav 1.000s
[087/101] target-85.wav 1.000s
[088/101] target-86.wav 1.000s
[089/101] target-87.wav 1.000s
[090/101] target-88.wav 1.000s
[091/101] target-89.wav 1.000s
[092/101] target-90.wav 1.000s
[093/101] target-91.wav 1.000s
[094/101] target-92.wav 1.000s
[095/101] target-93.wav 1.000s
[096/101] target-94.wav 1.000s
[097/101] target-95.wav 1.000s
[098/101] target-96.wav 1.000s
[099/101] target-97.wav 1.000s
[100/101] target-98.wav 1.000s
[101/101] target-99.wav 1.000s
ok
test_interruption_preserves_existing_files_and_cleans_temporary_data (test_neural_audio.GeneratorContract.test_interruption_preserves_existing_files_and_cleans_temporary_data) ... ok
test_invalid_pcm_never_reaches_publication (test_neural_audio.GeneratorContract.test_invalid_pcm_never_reaches_publication) ... ok
test_publication_failure_preserves_existing_files (test_neural_audio.GeneratorContract.test_publication_failure_preserves_existing_files) ... [001/101] intro.wav 1.000s
[002/101] target-0.wav 1.000s
[003/101] target-1.wav 1.000s
[004/101] target-2.wav 1.000s
[005/101] target-3.wav 1.000s
[006/101] target-4.wav 1.000s
[007/101] target-5.wav 1.000s
[008/101] target-6.wav 1.000s
[009/101] target-7.wav 1.000s
[010/101] target-8.wav 1.000s
[011/101] target-9.wav 1.000s
[012/101] target-10.wav 1.000s
[013/101] target-11.wav 1.000s
[014/101] target-12.wav 1.000s
[015/101] target-13.wav 1.000s
[016/101] target-14.wav 1.000s
[017/101] target-15.wav 1.000s
[018/101] target-16.wav 1.000s
[019/101] target-17.wav 1.000s
[020/101] target-18.wav 1.000s
[021/101] target-19.wav 1.000s
[022/101] target-20.wav 1.000s
[023/101] target-21.wav 1.000s
[024/101] target-22.wav 1.000s
[025/101] target-23.wav 1.000s
[026/101] target-24.wav 1.000s
[027/101] target-25.wav 1.000s
[028/101] target-26.wav 1.000s
[029/101] target-27.wav 1.000s
[030/101] target-28.wav 1.000s
[031/101] target-29.wav 1.000s
[032/101] target-30.wav 1.000s
[033/101] target-31.wav 1.000s
[034/101] target-32.wav 1.000s
[035/101] target-33.wav 1.000s
[036/101] target-34.wav 1.000s
[037/101] target-35.wav 1.000s
[038/101] target-36.wav 1.000s
[039/101] target-37.wav 1.000s
[040/101] target-38.wav 1.000s
[041/101] target-39.wav 1.000s
[042/101] target-40.wav 1.000s
[043/101] target-41.wav 1.000s
[044/101] target-42.wav 1.000s
[045/101] target-43.wav 1.000s
[046/101] target-44.wav 1.000s
[047/101] target-45.wav 1.000s
[048/101] target-46.wav 1.000s
[049/101] target-47.wav 1.000s
[050/101] target-48.wav 1.000s
[051/101] target-49.wav 1.000s
[052/101] target-50.wav 1.000s
[053/101] target-51.wav 1.000s
[054/101] target-52.wav 1.000s
[055/101] target-53.wav 1.000s
[056/101] target-54.wav 1.000s
[057/101] target-55.wav 1.000s
[058/101] target-56.wav 1.000s
[059/101] target-57.wav 1.000s
[060/101] target-58.wav 1.000s
[061/101] target-59.wav 1.000s
[062/101] target-60.wav 1.000s
[063/101] target-61.wav 1.000s
[064/101] target-62.wav 1.000s
[065/101] target-63.wav 1.000s
[066/101] target-64.wav 1.000s
[067/101] target-65.wav 1.000s
[068/101] target-66.wav 1.000s
[069/101] target-67.wav 1.000s
[070/101] target-68.wav 1.000s
[071/101] target-69.wav 1.000s
[072/101] target-70.wav 1.000s
[073/101] target-71.wav 1.000s
[074/101] target-72.wav 1.000s
[075/101] target-73.wav 1.000s
[076/101] target-74.wav 1.000s
[077/101] target-75.wav 1.000s
[078/101] target-76.wav 1.000s
[079/101] target-77.wav 1.000s
[080/101] target-78.wav 1.000s
[081/101] target-79.wav 1.000s
[082/101] target-80.wav 1.000s
[083/101] target-81.wav 1.000s
[084/101] target-82.wav 1.000s
[085/101] target-83.wav 1.000s
[086/101] target-84.wav 1.000s
[087/101] target-85.wav 1.000s
[088/101] target-86.wav 1.000s
[089/101] target-87.wav 1.000s
[090/101] target-88.wav 1.000s
[091/101] target-89.wav 1.000s
[092/101] target-90.wav 1.000s
[093/101] target-91.wav 1.000s
[094/101] target-92.wav 1.000s
[095/101] target-93.wav 1.000s
[096/101] target-94.wav 1.000s
[097/101] target-95.wav 1.000s
[098/101] target-96.wav 1.000s
[099/101] target-97.wav 1.000s
[100/101] target-98.wav 1.000s
[101/101] target-99.wav 1.000s
ok
test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests (test_neural_audio.GeneratorContract.test_rejects_incomplete_or_duplicate_or_unsafe_inventory_before_requests) ... ok
test_timeout_is_bounded_and_preserves_existing_files (test_neural_audio.GeneratorContract.test_timeout_is_bounded_and_preserves_existing_files) ... intro.wav: provider 시도 1/3 실패
intro.wav: provider 시도 2/3 실패
intro.wav: provider 시도 3/3 실패
ok
test_transient_provider_failures_retry_cleanly_with_bounded_backoff (test_neural_audio.GeneratorContract.test_transient_provider_failures_retry_cleanly_with_bounded_backoff) ... intro.wav: provider 시도 1/3 실패
intro.wav: provider 시도 2/3 실패
[001/101] intro.wav 1.000s
[002/101] target-0.wav 1.000s
[003/101] target-1.wav 1.000s
[004/101] target-2.wav 1.000s
[005/101] target-3.wav 1.000s
[006/101] target-4.wav 1.000s
[007/101] target-5.wav 1.000s
[008/101] target-6.wav 1.000s
[009/101] target-7.wav 1.000s
[010/101] target-8.wav 1.000s
[011/101] target-9.wav 1.000s
[012/101] target-10.wav 1.000s
[013/101] target-11.wav 1.000s
[014/101] target-12.wav 1.000s
[015/101] target-13.wav 1.000s
[016/101] target-14.wav 1.000s
[017/101] target-15.wav 1.000s
[018/101] target-16.wav 1.000s
[019/101] target-17.wav 1.000s
[020/101] target-18.wav 1.000s
[021/101] target-19.wav 1.000s
[022/101] target-20.wav 1.000s
[023/101] target-21.wav 1.000s
[024/101] target-22.wav 1.000s
[025/101] target-23.wav 1.000s
[026/101] target-24.wav 1.000s
[027/101] target-25.wav 1.000s
[028/101] target-26.wav 1.000s
[029/101] target-27.wav 1.000s
[030/101] target-28.wav 1.000s
[031/101] target-29.wav 1.000s
[032/101] target-30.wav 1.000s
[033/101] target-31.wav 1.000s
[034/101] target-32.wav 1.000s
[035/101] target-33.wav 1.000s
[036/101] target-34.wav 1.000s
[037/101] target-35.wav 1.000s
[038/101] target-36.wav 1.000s
[039/101] target-37.wav 1.000s
[040/101] target-38.wav 1.000s
[041/101] target-39.wav 1.000s
[042/101] target-40.wav 1.000s
[043/101] target-41.wav 1.000s
[044/101] target-42.wav 1.000s
[045/101] target-43.wav 1.000s
[046/101] target-44.wav 1.000s
[047/101] target-45.wav 1.000s
[048/101] target-46.wav 1.000s
[049/101] target-47.wav 1.000s
[050/101] target-48.wav 1.000s
[051/101] target-49.wav 1.000s
[052/101] target-50.wav 1.000s
[053/101] target-51.wav 1.000s
[054/101] target-52.wav 1.000s
[055/101] target-53.wav 1.000s
[056/101] target-54.wav 1.000s
[057/101] target-55.wav 1.000s
[058/101] target-56.wav 1.000s
[059/101] target-57.wav 1.000s
[060/101] target-58.wav 1.000s
[061/101] target-59.wav 1.000s
[062/101] target-60.wav 1.000s
[063/101] target-61.wav 1.000s
[064/101] target-62.wav 1.000s
[065/101] target-63.wav 1.000s
[066/101] target-64.wav 1.000s
[067/101] target-65.wav 1.000s
[068/101] target-66.wav 1.000s
[069/101] target-67.wav 1.000s
[070/101] target-68.wav 1.000s
[071/101] target-69.wav 1.000s
[072/101] target-70.wav 1.000s
[073/101] target-71.wav 1.000s
[074/101] target-72.wav 1.000s
[075/101] target-73.wav 1.000s
[076/101] target-74.wav 1.000s
[077/101] target-75.wav 1.000s
[078/101] target-76.wav 1.000s
[079/101] target-77.wav 1.000s
[080/101] target-78.wav 1.000s
[081/101] target-79.wav 1.000s
[082/101] target-80.wav 1.000s
[083/101] target-81.wav 1.000s
[084/101] target-82.wav 1.000s
[085/101] target-83.wav 1.000s
[086/101] target-84.wav 1.000s
[087/101] target-85.wav 1.000s
[088/101] target-86.wav 1.000s
[089/101] target-87.wav 1.000s
[090/101] target-88.wav 1.000s
[091/101] target-89.wav 1.000s
[092/101] target-90.wav 1.000s
[093/101] target-91.wav 1.000s
[094/101] target-92.wav 1.000s
[095/101] target-93.wav 1.000s
[096/101] target-94.wav 1.000s
[097/101] target-95.wav 1.000s
[098/101] target-96.wav 1.000s
[099/101] target-97.wav 1.000s
[100/101] target-98.wav 1.000s
[101/101] target-99.wav 1.000s
ok
test_wrong_edge_version_fails_before_network_or_asset_changes (test_neural_audio.GeneratorContract.test_wrong_edge_version_fails_before_network_or_asset_changes) ... ok
test_rejects_silence_clipping_bad_format_and_abnormal_duration (test_neural_audio.PCMContract.test_rejects_silence_clipping_bad_format_and_abnormal_duration) ... ok
test_valid_pcm_returns_measured_hash_bytes_duration_and_levels (test_neural_audio.PCMContract.test_valid_pcm_returns_measured_hash_bytes_duration_and_levels) ... ok
----------------------------------------------------------------------
Ran 18 tests in 2.699s
OK
@@ -0,0 +1,106 @@
> find-word@0.1.1 audio:generate
> .venv-audio/bin/python scripts/generate_audio.py
[001/101] intro.wav 7.056s
[002/101] luck-apple.wav 3.936s
[003/101] luck-sea.wav 3.984s
[004/101] luck-tree.wav 3.816s
[005/101] luck-hat.wav 3.984s
[006/101] luck-umbrella.wav 4.008s
[007/101] luck-market.wav 4.056s
[008/101] luck-oil.wav 3.960s
[009/101] luck-sound.wav 3.840s
[010/101] luck-meat.wav 3.912s
[011/101] luck-furniture.wav 3.888s
[012/101] password-apple.wav 4.896s
[013/101] password-sea.wav 4.848s
[014/101] password-tree.wav 4.872s
[015/101] password-hat.wav 4.896s
[016/101] password-umbrella.wav 4.992s
[017/101] password-market.wav 4.800s
[018/101] password-oil.wav 5.016s
[019/101] password-sound.wav 4.920s
[020/101] password-meat.wav 5.016s
[021/101] password-furniture.wav 4.872s
[022/101] remember-apple.wav 8.232s
[023/101] remember-sea.wav 8.328s
[024/101] remember-tree.wav 8.520s
[025/101] remember-hat.wav 8.376s
[026/101] remember-umbrella.wav 8.400s
[027/101] remember-market.wav 8.304s
[028/101] remember-oil.wav 8.328s
[029/101] remember-sound.wav 8.208s
[030/101] remember-meat.wav 8.232s
[031/101] remember-furniture.wav 8.400s
[032/101] last-apple.wav 7.416s
[033/101] last-sea.wav 7.200s
[034/101] last-tree.wav 7.968s
[035/101] last-hat.wav 7.392s
[036/101] last-umbrella.wav 7.728s
[037/101] last-market.wav 7.488s
[038/101] last-oil.wav 7.032s
[039/101] last-sound.wav 7.392s
[040/101] last-meat.wav 7.224s
[041/101] last-furniture.wav 7.440s
[042/101] first-apple.wav 7.488s
[043/101] first-sea.wav 7.272s
[044/101] first-tree.wav 7.896s
[045/101] first-hat.wav 7.440s
[046/101] first-umbrella.wav 7.632s
[047/101] first-market.wav 7.488s
[048/101] first-oil.wav 6.984s
[049/101] first-sound.wav 7.368s
[050/101] first-meat.wav 7.200s
[051/101] first-furniture.wav 7.584s
[052/101] repeat-apple.wav 8.280s
[053/101] repeat-sea.wav 7.968s
[054/101] repeat-tree.wav 8.832s
[055/101] repeat-hat.wav 8.256s
[056/101] repeat-umbrella.wav 8.544s
[057/101] repeat-market.wav 8.376s
[058/101] repeat-oil.wav 7.704s
[059/101] repeat-sound.wav 8.232s
[060/101] repeat-meat.wav 7.920s
[061/101] repeat-furniture.wav 8.280s
[062/101] correction-apple.wav 8.376s
[063/101] correction-sea.wav 8.304s
[064/101] correction-tree.wav 8.352s
[065/101] correction-hat.wav 8.304s
[066/101] correction-umbrella.wav 8.472s
[067/101] correction-market.wav 8.448s
[068/101] correction-oil.wav 8.472s
[069/101] correction-sound.wav 8.280s
[070/101] correction-meat.wav 8.400s
[071/101] correction-furniture.wav 8.304s
[072/101] middle-apple.wav 7.512s
[073/101] middle-sea.wav 7.224s
[074/101] middle-tree.wav 7.968s
[075/101] middle-hat.wav 7.368s
[076/101] middle-umbrella.wav 7.680s
[077/101] middle-market.wav 7.416s
[078/101] middle-oil.wav 6.960s
[079/101] middle-sound.wav 7.368s
[080/101] middle-meat.wav 7.128s
[081/101] middle-furniture.wav 7.392s
[082/101] message-apple.wav 10.776s
[083/101] message-sea.wav 10.776s
[084/101] message-tree.wav 11.256s
[085/101] message-hat.wav 10.800s
[086/101] message-umbrella.wav 10.896s
[087/101] message-market.wav 10.896s
[088/101] message-oil.wav 10.608s
[089/101] message-sound.wav 10.872s
[090/101] message-meat.wav 10.680s
[091/101] message-furniture.wav 10.872s
[092/101] mission-apple.wav 5.136s
[093/101] mission-sea.wav 5.064s
[094/101] mission-tree.wav 5.040s
[095/101] mission-hat.wav 5.112s
[096/101] mission-umbrella.wav 5.160s
[097/101] mission-market.wav 5.184s
[098/101] mission-oil.wav 5.040s
[099/101] mission-sound.wav 5.016s
[100/101] mission-meat.wav 5.088s
[101/101] mission-furniture.wav 5.040s
101개 신규 WAV 원자 교체 완료, 합계 34,898,524 바이트
+7
View File
@@ -0,0 +1,7 @@
tests/assets.test.ts 130ms
tests/neural-release.test.ts 12ms
tests/generator.test.ts 5ms
tests/App.test.tsx 91ms (unchanged)
tests/browser/game.spec.ts 30ms
tests/browser/ui.spec.ts 19ms
eslint.config.js 21ms (unchanged)
@@ -0,0 +1,12 @@
> find-word@0.1.1 test
> vitest run tests/neural-release.test.ts tests/App.test.tsx -t 0.1.1|브랜드|고정 venv
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.1.1
Test Files 2 passed (2)
Tests 3 passed | 12 skipped (15)
Start at 06:52:28
Duration 1.30s (environment 47%, tests 20%, setup 20%, transform 8%, import 4%, worker 1%)
+3
View File
@@ -0,0 +1,3 @@
> find-word@0.1.1 lint
> eslint . && tsc --noEmit
+1
View File
@@ -0,0 +1 @@
found 0 vulnerabilities
+15
View File
@@ -0,0 +1,15 @@
> find-word@0.1.1 test
> vitest run
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.1.1
Test Files 11 passed (11)
Tests 60 passed (60)
Start at 06:56:13
Duration 13.30s (tests 64%, environment 24%, setup 9%, transform 1%, import 1%, worker 1%)
Isolate 11 workers spawned · ~999ms startup each (spawn + environment, per file)
at least ~2.66s faster with isolate: false — reuses workers across files instead of one per file
@@ -0,0 +1,120 @@
PASS intro.wav: 7.056s, RMS=0.100000, peak=0.499847
PASS luck-apple.wav: 3.936s, RMS=0.100000, peak=0.401642
PASS luck-sea.wav: 3.984s, RMS=0.100000, peak=0.388702
PASS luck-tree.wav: 3.816s, RMS=0.100000, peak=0.369202
PASS luck-hat.wav: 3.984s, RMS=0.100000, peak=0.417084
PASS luck-umbrella.wav: 4.008s, RMS=0.100000, peak=0.385651
PASS luck-market.wav: 4.056s, RMS=0.100000, peak=0.402222
PASS luck-oil.wav: 3.960s, RMS=0.100000, peak=0.381714
PASS luck-sound.wav: 3.840s, RMS=0.100000, peak=0.386322
PASS luck-meat.wav: 3.912s, RMS=0.100000, peak=0.371124
PASS luck-furniture.wav: 3.888s, RMS=0.100000, peak=0.387054
PASS password-apple.wav: 4.896s, RMS=0.100000, peak=0.483429
PASS password-sea.wav: 4.848s, RMS=0.100000, peak=0.533905
PASS password-tree.wav: 4.872s, RMS=0.100000, peak=0.490387
PASS password-hat.wav: 4.896s, RMS=0.100000, peak=0.505890
PASS password-umbrella.wav: 4.992s, RMS=0.100000, peak=0.477661
PASS password-market.wav: 4.800s, RMS=0.100000, peak=0.481689
PASS password-oil.wav: 5.016s, RMS=0.100000, peak=0.494507
PASS password-sound.wav: 4.920s, RMS=0.100000, peak=0.462097
PASS password-meat.wav: 5.016s, RMS=0.100000, peak=0.497864
PASS password-furniture.wav: 4.872s, RMS=0.100000, peak=0.483643
PASS remember-apple.wav: 8.232s, RMS=0.100000, peak=0.563568
PASS remember-sea.wav: 8.328s, RMS=0.100000, peak=0.546539
PASS remember-tree.wav: 8.520s, RMS=0.100000, peak=0.548645
PASS remember-hat.wav: 8.376s, RMS=0.100000, peak=0.541779
PASS remember-umbrella.wav: 8.400s, RMS=0.100000, peak=0.557831
PASS remember-market.wav: 8.304s, RMS=0.100000, peak=0.572815
PASS remember-oil.wav: 8.328s, RMS=0.100000, peak=0.524384
PASS remember-sound.wav: 8.208s, RMS=0.100000, peak=0.537781
PASS remember-meat.wav: 8.232s, RMS=0.100000, peak=0.519287
PASS remember-furniture.wav: 8.400s, RMS=0.100000, peak=0.561890
PASS last-apple.wav: 7.416s, RMS=0.100000, peak=0.622528
PASS last-sea.wav: 7.200s, RMS=0.100000, peak=0.591034
PASS last-tree.wav: 7.968s, RMS=0.100000, peak=0.580750
PASS last-hat.wav: 7.392s, RMS=0.100000, peak=0.550079
PASS last-umbrella.wav: 7.728s, RMS=0.100000, peak=0.597656
PASS last-market.wav: 7.488s, RMS=0.100000, peak=0.600555
PASS last-oil.wav: 7.032s, RMS=0.100000, peak=0.557068
PASS last-sound.wav: 7.392s, RMS=0.100000, peak=0.564087
PASS last-meat.wav: 7.224s, RMS=0.100000, peak=0.537201
PASS last-furniture.wav: 7.440s, RMS=0.100000, peak=0.583588
PASS first-apple.wav: 7.488s, RMS=0.100000, peak=0.579773
PASS first-sea.wav: 7.272s, RMS=0.100000, peak=0.571777
PASS first-tree.wav: 7.896s, RMS=0.100000, peak=0.583344
PASS first-hat.wav: 7.440s, RMS=0.100000, peak=0.531250
PASS first-umbrella.wav: 7.632s, RMS=0.100000, peak=0.570007
PASS first-market.wav: 7.488s, RMS=0.100000, peak=0.639069
PASS first-oil.wav: 6.984s, RMS=0.100000, peak=0.534729
PASS first-sound.wav: 7.368s, RMS=0.100000, peak=0.518951
PASS first-meat.wav: 7.200s, RMS=0.100000, peak=0.513123
PASS first-furniture.wav: 7.584s, RMS=0.100000, peak=0.570038
PASS repeat-apple.wav: 8.280s, RMS=0.100000, peak=0.641449
PASS repeat-sea.wav: 7.968s, RMS=0.100000, peak=0.684326
PASS repeat-tree.wav: 8.832s, RMS=0.100000, peak=0.618744
PASS repeat-hat.wav: 8.256s, RMS=0.100000, peak=0.616730
PASS repeat-umbrella.wav: 8.544s, RMS=0.100000, peak=0.674835
PASS repeat-market.wav: 8.376s, RMS=0.100000, peak=0.682251
PASS repeat-oil.wav: 7.704s, RMS=0.100000, peak=0.623962
PASS repeat-sound.wav: 8.232s, RMS=0.100000, peak=0.611450
PASS repeat-meat.wav: 7.920s, RMS=0.100000, peak=0.592102
PASS repeat-furniture.wav: 8.280s, RMS=0.100000, peak=0.667023
PASS correction-apple.wav: 8.376s, RMS=0.100000, peak=0.490326
PASS correction-sea.wav: 8.304s, RMS=0.100000, peak=0.496155
PASS correction-tree.wav: 8.352s, RMS=0.100000, peak=0.470612
PASS correction-hat.wav: 8.304s, RMS=0.100000, peak=0.470978
PASS correction-umbrella.wav: 8.472s, RMS=0.100000, peak=0.479034
PASS correction-market.wav: 8.448s, RMS=0.100000, peak=0.491486
PASS correction-oil.wav: 8.472s, RMS=0.100000, peak=0.470795
PASS correction-sound.wav: 8.280s, RMS=0.100000, peak=0.469269
PASS correction-meat.wav: 8.400s, RMS=0.100000, peak=0.481537
PASS correction-furniture.wav: 8.304s, RMS=0.100000, peak=0.487396
PASS middle-apple.wav: 7.512s, RMS=0.100000, peak=0.553558
PASS middle-sea.wav: 7.224s, RMS=0.100000, peak=0.564941
PASS middle-tree.wav: 7.968s, RMS=0.100000, peak=0.600006
PASS middle-hat.wav: 7.368s, RMS=0.100000, peak=0.555206
PASS middle-umbrella.wav: 7.680s, RMS=0.100000, peak=0.569550
PASS middle-market.wav: 7.416s, RMS=0.100000, peak=0.594971
PASS middle-oil.wav: 6.960s, RMS=0.100000, peak=0.539917
PASS middle-sound.wav: 7.368s, RMS=0.100000, peak=0.534821
PASS middle-meat.wav: 7.128s, RMS=0.100000, peak=0.510834
PASS middle-furniture.wav: 7.392s, RMS=0.100000, peak=0.557617
PASS message-apple.wav: 10.776s, RMS=0.100000, peak=0.525360
PASS message-sea.wav: 10.776s, RMS=0.100000, peak=0.535217
PASS message-tree.wav: 11.256s, RMS=0.100000, peak=0.526245
PASS message-hat.wav: 10.800s, RMS=0.100000, peak=0.587006
PASS message-umbrella.wav: 10.896s, RMS=0.100000, peak=0.530365
PASS message-market.wav: 10.896s, RMS=0.100000, peak=0.534821
PASS message-oil.wav: 10.608s, RMS=0.100000, peak=0.518127
PASS message-sound.wav: 10.872s, RMS=0.100000, peak=0.519531
PASS message-meat.wav: 10.680s, RMS=0.100000, peak=0.514771
PASS message-furniture.wav: 10.872s, RMS=0.100000, peak=0.529327
PASS mission-apple.wav: 5.136s, RMS=0.100000, peak=0.470154
PASS mission-sea.wav: 5.064s, RMS=0.100000, peak=0.450134
PASS mission-tree.wav: 5.040s, RMS=0.100000, peak=0.458527
PASS mission-hat.wav: 5.112s, RMS=0.100000, peak=0.449829
PASS mission-umbrella.wav: 5.160s, RMS=0.100000, peak=0.465332
PASS mission-market.wav: 5.184s, RMS=0.100000, peak=0.485687
PASS mission-oil.wav: 5.040s, RMS=0.100000, peak=0.443573
PASS mission-sound.wav: 5.016s, RMS=0.100000, peak=0.454803
PASS mission-meat.wav: 5.088s, RMS=0.100000, peak=0.441864
PASS mission-furniture.wav: 5.040s, RMS=0.100000, peak=0.485229
{
"count": 101,
"newVsV01": 101,
"uniqueHashes": 101,
"bytes": 34898524,
"durationRange": [
3.816,
11.256
],
"rmsRange": [
0.09999985338851038,
0.10000004859108667
],
"peakRange": [
0.36920166015625,
0.684326171875
],
"historicalUnchanged": 115
}
+15
View File
@@ -0,0 +1,15 @@
> find-word@0.1.1 build
> tsc --noEmit && vite build && node scripts/check-build.mjs
vite v8.3.4 building client environment for production...
transforming...
✓ 20 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 0.89 kB │ gzip: 0.63 kB
dist/assets/index-KT6VDfPn.css 15.25 kB │ gzip: 4.39 kB
dist/assets/index-CorsjeLi.js 245.34 kB │ gzip: 77.26 kB
✓ built in 405ms
빌드 음성 자산 101개 및 런타임 notice 전문 확인
+77
View File
@@ -0,0 +1,77 @@
> find-word@0.1.1 test:browser
> playwright test
[WebServer] (node:789414) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
Running 12 tests using 2 workers
(node:789465) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:789464) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-usRFeJ --remote-debugging-pipe --no-startup-window +0ms
pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-tgmIGX --remote-debugging-pipe --no-startup-window +0ms
pw:browser <launched> pid=789488 +15ms
pw:browser <launched> pid=789490 +14ms
pw:browser [pid=789488][err] [789574:789574:1014/065656.619803:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +253ms
pw:browser [pid=789490][err] [789572:789572:1014/065656.641388:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +270ms
pw:browser [pid=789488][err] [789657:7:1014/065657.003307:ERROR:gpu/ipc/client/command_buffer_proxy_impl.cc:287] ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer. +394ms
pw:browser [pid=789490][err] [789697:789697:1014/065657.581581:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +937ms
pw:browser [pid=789488][err] [789721:789721:1014/065659.123843:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +2s
pw:browser [pid=789490][err] [789490:789531:1014/065701.312194:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +4s
pw:browser [pid=789488][err] [789488:789553:1014/065702.399765:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +3s
✓ 2 [desktop] › tests/browser/game.spec.ts:114:1 › 오디오 HTTP 실패를 화면에 표시하고 재시도한다 (14.7s)
✓ 3 [desktop] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (309ms)
✓ 4 [desktop] › tests/browser/ui.spec.ts:4:1 › 전체 음량은 설정 흐름 안에 들어가며 키보드로 조절된다 (1.6s)
✓ 5 [desktop] › tests/browser/ui.spec.ts:52:1 › 난이도 설명은 모바일에서도 보인다 (1.0s)
pw:browser [pid=789490][err] [789490:789531:1014/065725.821501:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +25s
pw:browser [pid=789488][err] [789488:789553:1014/065728.796251:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: QUOTA_EXCEEDED +26s
✓ 6 [desktop] › tests/browser/ui.spec.ts:68:1 › 한국어 제목은 단어 중간에서 줄바꿈하지 않는다 (16.7s)
pw:browser [pid=789490] <gracefully close start> +5s
pw:browser [pid=789490] <process did exit: exitCode=0, signal=null> +53ms
pw:browser [pid=789490] starting temporary directories cleanup +0ms
pw:browser [pid=789490] finished temporary directories cleanup +9ms
pw:browser [pid=789490] <gracefully close end> +0ms
(node:789845) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-WzJ5B4 --remote-debugging-pipe --no-startup-window +0ms
pw:browser <launched> pid=789857 +13ms
pw:browser [pid=789857][err] [789900:789900:1014/065731.887141:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +138ms
pw:browser [pid=789857][err] [789972:789972:1014/065733.402085:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +2s
pw:browser [pid=789857][err] [789857:789885:1014/065736.698476:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +3s
pw:browser [pid=789857][err] [789857:789885:1014/065757.253598:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +21s
✓ 1 [desktop] › tests/browser/game.spec.ts:7:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 (1.6m)
pw:browser [pid=789488] <gracefully close start> +1m
pw:browser [pid=789488] <process did exit: exitCode=0, signal=null> +49ms
pw:browser [pid=789488] starting temporary directories cleanup +1ms
pw:browser [pid=789488] finished temporary directories cleanup +10ms
pw:browser [pid=789488] <gracefully close end> +0ms
(node:790149) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-F4j9tO --remote-debugging-pipe --no-startup-window +0ms
pw:browser <launched> pid=790161 +5ms
pw:browser [pid=790161][err] [790203:790203:1014/065834.688015:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +137ms
pw:browser [pid=790161][err] [790242:7:1014/065834.832706:ERROR:gpu/ipc/client/command_buffer_proxy_impl.cc:287] ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer. +143ms
pw:browser [pid=790161][err] [790262:790262:1014/065835.186112:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +352ms
pw:browser [pid=789857][err] [789857:789885:1014/065837.765817:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +41s
pw:browser [pid=790161][err] [790161:790189:1014/065838.519301:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: QUOTA_EXCEEDED +3s
✓ 8 [mobile] › tests/browser/game.spec.ts:114:1 › 오디오 HTTP 실패를 화면에 표시하고 재시도한다 (16.9s)
✓ 9 [mobile] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (292ms)
✓ 10 [mobile] › tests/browser/ui.spec.ts:4:1 › 전체 음량은 설정 흐름 안에 들어가며 키보드로 조절된다 (938ms)
✓ 11 [mobile] › tests/browser/ui.spec.ts:52:1 › 난이도 설명은 모바일에서도 보인다 (921ms)
✓ 12 [mobile] › tests/browser/ui.spec.ts:68:1 › 한국어 제목은 단어 중간에서 줄바꿈하지 않는다 (16.7s)
pw:browser [pid=790161] <gracefully close start> +32s
pw:browser [pid=790161] <process did exit: exitCode=0, signal=null> +51ms
pw:browser [pid=790161] starting temporary directories cleanup +0ms
pw:browser [pid=790161] finished temporary directories cleanup +9ms
pw:browser [pid=790161] <gracefully close end> +0ms
✓ 7 [mobile] › tests/browser/game.spec.ts:7:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 (1.7m)
pw:browser [pid=789857] <gracefully close start> +34s
pw:browser [pid=789857] <process did exit: exitCode=0, signal=null> +107ms
pw:browser [pid=789857] starting temporary directories cleanup +1ms
pw:browser [pid=789857] finished temporary directories cleanup +18ms
pw:browser [pid=789857] <gracefully close end> +1ms
12 passed (2.3m)
@@ -0,0 +1,21 @@
2026-10-14T06:56:54.062Z pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-jPkOZ2 --remote-debugging-pipe --no-startup-window
2026-10-14T06:56:54.067Z pw:browser <launched> pid=789288
2026-10-14T06:56:54.238Z pw:browser [pid=789288][err] [789341:789341:1014/065654.236997:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7
2026-10-14T06:56:54.428Z pw:browser [pid=789288][err] [789379:7:1014/065654.427988:ERROR:gpu/ipc/client/command_buffer_proxy_impl.cc:287] ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer.
SANDBOX STATUS
Sandbox Status
Layer 1 Sandbox Namespace
PID namespaces Yes
Network namespaces Yes
Seccomp-BPF sandbox Yes
Seccomp-BPF sandbox supports TSYNC Yes
Ptrace Protection with Yama LSM (Broker) Yes
Ptrace Protection with Yama LSM (Non-broker) No
You are adequately sandboxed.
PASS: sandboxed Chrome decoded 101/101 WAVs at 24kHz mono; hashes, bytes, duration, RMS, peak verified; external requests=0, JS errors=0.
2026-10-14T06:56:57.008Z pw:browser [pid=789288] <gracefully close start>
2026-10-14T06:56:57.243Z pw:browser [pid=789288] <process did exit: exitCode=0, signal=null>
2026-10-14T06:56:57.243Z pw:browser [pid=789288] starting temporary directories cleanup
2026-10-14T06:56:57.285Z pw:browser [pid=789288] finished temporary directories cleanup
2026-10-14T06:56:57.286Z pw:browser [pid=789288] <gracefully close end>
+3
View File
@@ -0,0 +1,3 @@
> find-word@0.1.1 lint
> eslint . && tsc --noEmit
@@ -0,0 +1,9 @@
{
"historicalFilesUnchanged": 115,
"gitHeadUnchanged": "1c0069c367f6e108d3f67a2a0d044399dd0ef2bd",
"branch": "fix/v0.1.1-neural-voice",
"secretScanTextFiles": 40,
"secretMatches": 0,
"publicStageDirectories": 0,
"pythonVenvVersion": "7.3.1"
}
+12
View File
@@ -0,0 +1,12 @@
Linux-6.8.0-142-generic-x86_64-with-glibc2.39
Generated at: 2026-10-14T06:55:41.751382+00:00
$ node --version
v26.7.0
$ npm --version
11.19.0
$ .venv-audio/bin/python --version
Python 3.11.16
$ .venv-audio/bin/python -m pip check
No broken requirements found.
$ google-chrome --version
Google Chrome 146.0.7680.80
@@ -0,0 +1,17 @@
{
"historicalFilesUnchanged": 115,
"gitHeadUnchanged": "1c0069c367f6e108d3f67a2a0d044399dd0ef2bd",
"branch": "fix/v0.1.1-neural-voice",
"chromeLaunchesWithSandbox": 5,
"browserTestsPassed": 12,
"browserRuntimeSandbox": [
"Namespace",
"PID namespaces",
"Network namespaces",
"Seccomp-BPF"
],
"documentLinksChecked": 56,
"gameMechanicsAndRuntimeAudioUnchanged": true,
"distContainsOnlyExpectedArtifacts": true,
"diffCheck": "PASS"
}
File diff suppressed because it is too large Load Diff
+738
View File
@@ -0,0 +1,738 @@
{
"historical": {
".agent/evidence/01-content-green.log": "5585acd257b49225218835acd69a1d240c7737d12dba62949f31a5b7c1c9ed2a",
".agent/evidence/01-content-red.log": "0f28fe2ae2c4669a52ba2fc15bfa6285e4922474dc2b2571098b522679948e12",
".agent/evidence/02-game-green.log": "5ca5895f8a09f4e9de7a846bf9ab37fb3715623e8e7654dab095505c097fc0c7",
".agent/evidence/02-game-red.log": "78468ee5c25c1685f3613926f636b6fb4569227533feda3547afc6b8123d6452",
".agent/evidence/03-dsp-green.log": "d3d08683a1426b845a2e987572861b82b3ac978b8c352991950c0f32a473d3de",
".agent/evidence/03-dsp-intermediate.log": "084a52294f718718256eb1516048a672d045a5f7dcb5d11c646092d29efbab58",
".agent/evidence/03-dsp-red.log": "bacf42e5c808d32702b9bcd30523d1fcf17d5ff75b281233d9e84f33b6e42589",
".agent/evidence/04-audio-green.log": "d48c93fa7d32315ed4f719dee19222e7398bc4c4bceb8cf345e0e221a9ac89d8",
".agent/evidence/04-audio-red.log": "58bbf8eae572f83e408dd101eac738a5f6963550e21c8265f42a7eeba18be7a7",
".agent/evidence/05-assets-red.log": "04388acb098f7dabe9a35783b496075ee7c39757d3fde5361c9ac080188ac371",
".agent/evidence/06-ui-05-assets-green.log": "ced2ad738cda673b24308dcb9d99d59e3ae918709eeb32de359d6ab1022133e2",
".agent/evidence/06-ui-intermediate.log": "3295b3ae691dadb8feb7f0aaf604a1aa56cbfae27b5dbdd486cb5645f5edabe9",
".agent/evidence/06-ui-red.log": "1f1ed6bd440af22f5abf59e4be194f969bee1d115d436a155d879d8cffddb747",
".agent/evidence/07-build-green.log": "ec98087d20a68c5b81c6c23406316f1e5f19c6124498e1fc005d04bb78894a57",
".agent/evidence/07-build-red.log": "138802de7bc67c1535668efe7a915424a70d5d7994acb7f366a139e89c1da77f",
".agent/evidence/08-rule-green.log": "91b7ce3fda181fbe51cbe4e6debb61dd44dd55226dcfa81ed73559ba76811f3f",
".agent/evidence/08-rule-red.log": "2cc1854cf6a4b9e8d53a7a36b1dde1fb6c6970b89f841b9e8f404e6e42bb929e",
".agent/evidence/09-ime-green.log": "e5d5d1cfa2b6db724ded97d5f3309a517bcf637d9b2b417e9110dc9da0a48d72",
".agent/evidence/09-ime-red.log": "10e5f9f99609044c768cd338df0d574a06a7442e0debe0e61ca16a6b5873adf3",
".agent/evidence/10-ime-reset-green.log": "e12761b3a2814a79d1448e7452474a086bf371921287718eb72dd9b0f6b8fc82",
".agent/evidence/10-ime-reset-red.log": "f6cb7c1724b8f9c410385e9970051577c03527fb7e719f43a77c967ca08ef18f",
".agent/evidence/11-provenance-green.log": "54dcc417b97f82422c5c3e0ae11caa1f15a60412853ea1dc0152d15031bcd935",
".agent/evidence/11-provenance-red.log": "e69fa7989223e659c16b8030f8668e562ad5b0daa060fbb1c9eff41a37fd56fd",
".agent/evidence/12-ime-replay-green.log": "a93d9f16c7d81ed5e9a7c0b70ffee1e393d2943ddf3149a5bb115c5517327c44",
".agent/evidence/12-ime-replay-red.log": "8cf5dab06d93cc544c21276ee633829f8b137b4b6d7c5fe47aadcad6fc2afb71",
".agent/evidence/13-heading-build-after.log": "19829ac264f97aa023baf7d5e1fd429343272f3bd952e8b6dfb9eec0f594b453",
".agent/evidence/13-heading-build-before.log": "646d197d2ef93c19fec4719e20297de1b22eff54f3e6155ba2125fd3dd372c46",
".agent/evidence/13-heading-green.log": "d59fa8546083e9d371c7a552287f27bf3acd572bd0cce3da8eba860da5c05880",
".agent/evidence/13-heading-red.log": "33acc2838786a87b8ecc170a1ac0a9d7521daf8e5b9aed2195e76e45ea327f76",
".agent/evidence/14-snr-browser-green.log": "fcb82296e9af4b96112fae0bbb77c6ba41230c117021243e85916ae1130a462d",
".agent/evidence/14-snr-browser-red.log": "36298e5bb1f45a69b0ca75e5cbce85ee1455c4485759670268fbbcf55bacd4d4",
".agent/evidence/14-snr-build.log": "1e9ce36a48904a58195f9d1c2d9ca6cf2895fcb8bd0b5ab9b72f76e92c6b2585",
".agent/evidence/14-snr-green.log": "ae74e57cea20841299a8c1ee5eaf60efad34bda697339f45527cdec83578e6df",
".agent/evidence/14-snr-red.log": "b39bdbd8815d0d9cfcedc41c61124afece2011ea6c6c250b0ee0139eae7e9edd",
".agent/evidence/15-volume-browser-green.log": "aeccd5f13eb9db4062cbf2c70eee332d0c39540d580e113d0a79a899b2ef02de",
".agent/evidence/15-volume-browser-red.log": "84954280c1729703f9e9c2680c8933c3b0752b19fb9c3562e7dbf2ea1b4a548c",
".agent/evidence/15-volume-build.log": "2767b794124804b3447f529eef025e2530975fcc506e1cbe8994acf8243e6ba8",
".agent/evidence/15-volume-green.log": "0f9a90923f4fdc477c8f2436653eb2bf0e4b251bcb52e795701309ba14f23c7d",
".agent/evidence/15-volume-red.log": "9beae6305080cd0d869bf3fd2093beb6e2e25e5424223aa7e4ad4db96954f37e",
".agent/evidence/16-copy-green.log": "dacbdbab5d4af2b6e19eb4e0502a70720aac9fb6cf3b9d6dfdc73a5bf7edabfe",
".agent/evidence/16-copy-red.log": "ebe3d7c86938d33d7f1a4818b18c7e94ab8feb18bee099fcb535a93d8083861b",
".agent/evidence/17-spacing-green.log": "8ab85362ceadcdfecf4f7b1e95abfb4237e15018692e14f937be90265c351b11",
".agent/evidence/17-spacing-red.log": "12db8083cd8627a81a52cd32358780a3c2257cb3bd702350b190b39226f6550f",
".agent/evidence/18-literal-green.log": "878a8d788a8cedbf652fe0e819fe482099249a52ae7b5cc3d8826e64b32c6377",
".agent/evidence/18-literal-red.log": "ad23ae7be3d9aab83907c12849012a01f9d1b12e5a174c3acede89817a74d2d2",
".agent/evidence/19-notices-green.log": "efc51aca0738f3cb5264ec3c3ad0d17bb150d685f5fdb5e200bc1eedc0e3c02b",
".agent/evidence/19-notices-red.log": "8f34c583cb8563803828d72fe56622d84bcf59a9541d983d6c0b705225955794",
".agent/evidence/20-audio-generate.log": "f864fc266f7ca50c600457399f198a77949e9ee1601b0d2fc19b64942a2030cb",
".agent/evidence/20-audio-green.log": "edb9b9f0aa1af11835960eee9bb6e8c013341aa528d2857bac0b89ac38457528",
".agent/evidence/20-audio-red.log": "c1cbd5b585e8a70e23b88bfcee0c6479f85fdec0d1e06d13c81c689a140c0ac0",
".agent/evidence/20-mechanics-green.log": "9776c68143f668e35df8b2e19884b25d2369e4800b4c264e635d0c260818c5f1",
".agent/evidence/20-mechanics-red.log": "d25a1c844366e14fe1db9bb7c243fe0adb6857ee5b4548cf2865de96589af647",
".agent/evidence/21-node-green.log": "3c36e9e45b6844ae2c184f943b61195482d9de53ceab06221093c8281d210d73",
".agent/evidence/21-node-red.log": "ee25556037bdbd6b099dbb087a522284e8df00bd573dfcf0e42c734e31e09e84",
".agent/evidence/22-sandbox-green.log": "e8a1a17e49c22dea81d7f85111c744473427466791ddeda75047cd0082e7faba",
".agent/evidence/22-sandbox-red.log": "c8a97270f0f68367d6edb3e5ee10f34bbda1127f8dae2c5639afd482198e7bcd",
".agent/evidence/23-delivery-browser-red.log": "180a61bbacf85db9e52f721b50da683103b719bc350454cc99d4c8954b2ae86e",
".agent/evidence/24-retry-audio-budget.log": "b9241872b4ecd80265df4c6c2be90b31e9de4d0754772655e50b7fb4f05e2d3b",
".agent/evidence/24-retry-final-browser.log": "68029aae89adf86fd60ee56a20a1e2f769cb4f894f27ae23963ca5b5b58c62c4",
".agent/evidence/24-retry-final-build.log": "702c20554872e437137097ca59a80d911188477f018bc48c4b49a770b73d5a84",
".agent/evidence/24-retry-final-lint.log": "8682ca1f55e3ec58f13321cc339c8647ef72c1934d74ea9b980aee717e528819",
".agent/evidence/24-retry-final-test.log": "b71bb1375a039bcc3d7b3c5070da85ece3551f32ae1b8bb3a2abc5ef1edd57b8",
".agent/evidence/24-retry-integrity.log": "a188fe54dce05f6caa868b3d9f2c22a852f6a8cdc462355673316578be623a08",
".agent/evidence/24-retry-targeted-green.log": "4e53f2de988040540f5075b2e4a483ca53b671486c35e864fbc3c2c9c5361c61",
".agent/evidence/audio-reproduce.log": "5f5726f3ed6845882c7a6d6f9a8d898c2b73bf61fa6328e8bbafd25f61ed4268",
".agent/evidence/browser-final.log": "9273c91613160e239027452894b3735f9657ccad97a52412eb889290aebd5adf",
".agent/evidence/browser-first.log": "f3087028d76aae36d61d7a14da488bd809079a9e121a2d8fb01fa034f99d4f05",
".agent/evidence/browser-second.log": "2ff1d16f51b9384cf431d5923ad87d773510fe4b89bdf62f09cbda2efae20e3b",
".agent/evidence/browser-third.log": "1b6c264930da8934e7f1c8da6c998543f35e68b1c3159dad722cfe23a8e5244c",
".agent/evidence/changed-files.txt": "2b609231e5c7becd581f79413a4f7443312e71f0099ac6a51b2c5f0dfdee576f",
".agent/evidence/desktop-game.png": "42702e89264357257db8bf54c2b3743e3212e62cfd3476a8c25bad83fb59ff81",
".agent/evidence/desktop-home.png": "bf2f515fcd483cd5ca9a3b408f484d3556b75b1be0bb70360b7fd5f7c3404993",
".agent/evidence/desktop-results.png": "003df3aeb08ce66618775377d9b2003809d696629f61cf54b7b86e7a0ed63593",
".agent/evidence/final-audit.log": "6d8c5c8f3d7684adb070417bd608d01ae90aa3dc26a65af03ffda4955f38d9a3",
".agent/evidence/final-browser.log": "5855691def462b23667a9d658338a0458a53d984b5b5f7e11b45f9a63092abcd",
".agent/evidence/final-build.log": "565a95a51a10f78bc08f256755afce5ef183440dcdea5e75b3aefde8d7c5b837",
".agent/evidence/final-lint.log": "d2354c241320f11f07890cbf32f99a5d88f1c7f4f236d860e2cd26db739badd8",
".agent/evidence/final-security.log": "c585566624a4596e97327fb1864b1ac2a3189c0794b1e25a9d6ff1abb86046cb",
".agent/evidence/final-test.log": "af03027cb22a090ecd107c10e3fc7e2f9ceb394122b0b73caa7d362310504170",
".agent/evidence/mobile-game.png": "20a3f02f70a28b2faae1b33d0d4d6fea10b77caa426e4bf9faa5ef6d4474a846",
".agent/evidence/mobile-home.png": "7f84bd54183fcdd03fe136b41145146ddfb323041c96a8b9e6b670c9a923033a",
".agent/evidence/mobile-results.png": "ec2938c03ac03da8e33e25f043522b317b60c16be1c29f9dd325a81ae84513a8",
".agent/evidence/neo-before-spacing-browser.log": "e5c214f14bd93ef1bb731f87ecfd3a02d299c9f9e5a788233f6eda5eb8946b4f",
".agent/evidence/neo-desktop-game.png": "f5966688ba46f14fab5125452f935e55f6e6dc4355c876416729866129daea70",
".agent/evidence/neo-desktop-heading.png": "db609f2f54af0e6b1bb96bce9bf839454403d6e2787e6520a2928fad31beb021",
".agent/evidence/neo-desktop-home.png": "826c5da794c4ea3c15bd6c13e81d1c021fbeb8a902fc4908b78f9c457f091c0f",
".agent/evidence/neo-desktop-results.png": "98a68ca050a4e66c17dcc3f1bd5f0e86bfc88c2ebe9a75284766d17e10426632",
".agent/evidence/neo-final-browser.log": "582e7cbb643201e4b197b566b021322448abaae0b383967ad0e816d0c351e96b",
".agent/evidence/neo-final-build.log": "f30138e53b8c12e70e80e2cd5f4bdfcf8d1f6a095216a4f9ade6687bca1f0488",
".agent/evidence/neo-final-lint.log": "d2354c241320f11f07890cbf32f99a5d88f1c7f4f236d860e2cd26db739badd8",
".agent/evidence/neo-final-test.log": "f718e2acda255fcba67b272c7fa625af450714b384bb67a72f09328bf6964f0b",
".agent/evidence/neo-intermediate-build.log": "9d8a1f0586d58196e03e45330b6e8ff5522fdd3c27870aae2fb052199f8cf5cb",
".agent/evidence/neo-intermediate-lint.log": "5e94ea847c3a092f4ff8e97ac5b61ebef805b3c859ad38461f4a437045d1b5b9",
".agent/evidence/neo-mobile-game.png": "1a6733a3293204e4841ec8722a1ffe37033943097c691bcfadbcd907fde024ef",
".agent/evidence/neo-mobile-heading.png": "ae07d0a1cb6f835525c7e0ef31655a543eaa9e10183596c2d409dead6faccf15",
".agent/evidence/neo-mobile-home.png": "9b3ba8b0a9f7b321882429e31ac4a0472fcc13a998dfadfc930c273bc37558d4",
".agent/evidence/neo-mobile-results.png": "d49fdf6ae9566d7a2003db3f252d84ed88ac4d73a0390ce404b47e7bab9c60df",
".agent/evidence/release-desktop-game.png": "7300a06a507f651a587ed3deb36cc5bb728f4a36c30b7b1cf409a3b209ba564c",
".agent/evidence/release-desktop-heading.png": "de454d77e29737e23c573646404489d5682004521deabfa01b439d607faa32ca",
".agent/evidence/release-desktop-home.png": "f28f744e11b66373ee8db6eda2f7bdc384da4f7e763fbb467a4cda30090e869b",
".agent/evidence/release-desktop-results.png": "2ebb4056d0ecdadea8a3469500801065ae158c17cd2db27817e813e53adc71f3",
".agent/evidence/release-docs-final.log": "3529acce5befee536ec7d8e9d22cbbf27182297bb07408ab6e31551aaee76ed3",
".agent/evidence/release-final-audit.log": "6d8c5c8f3d7684adb070417bd608d01ae90aa3dc26a65af03ffda4955f38d9a3",
".agent/evidence/release-final-browser.log": "2a9881cef8c379f41abf5d69dd5ad21881988f78c0579c95e463121dc37f6e09",
".agent/evidence/release-final-build.log": "3fba8356382341db9c562d985ca2229fd0b81969532746b0146bc489d54c321e",
".agent/evidence/release-final-lint.log": "d2354c241320f11f07890cbf32f99a5d88f1c7f4f236d860e2cd26db739badd8",
".agent/evidence/release-final-test.log": "46d5d0fc0180adc00a734b64db4acb4cbaa37d12567d0224836306312213870c",
".agent/evidence/release-format.log": "57658c36cb3161b53cdf934017e4b7a733a273509ace184e0a2a6eaa046c742b",
".agent/evidence/release-integrity.log": "cc77121b43a6b24a358999cf1a3bbf701d467fcee9730095f318303c2e80602b",
".agent/evidence/release-intermediate-lint.log": "ee597e984ebdf11ea247c8cb1551cda446580cbd7a3dc708f85fa78bb72700ad",
".agent/evidence/release-mobile-game.png": "83a918e5ff2142e540cd12b85806b3e69a71bc66df5d241f4b2f5abdaf493f82",
".agent/evidence/release-mobile-heading.png": "d5c92a3b62f749d5f064af12efa5a1a2ad13b177270ec01dd10a549a8437899d",
".agent/evidence/release-mobile-home.png": "c7fc37a247bbadba60de9dff3c8d87930a2e6ebb868f687a4135b3fd035ed1c3",
".agent/evidence/release-mobile-results.png": "587956c9ad5eca054e4bb4b44748a2c637655e407427ba5b4c6ad7bf5a74539a",
".agent/RESULT.md": "eef6d73a67a8a7e90cd7b4747debc5976cc51571bc268328634413f698d0e311"
},
"audio": {
"generator": "eSpeak NG ko, speed 145, pitch 45, amplitude 100; FFmpeg PCM 16kHz mono s16",
"toolVersions": {
"espeak": "eSpeak NG text-to-speech: 1.51",
"ffmpeg": "ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2023 the FFmpeg developers"
},
"source": "https://github.com/espeak-ng/espeak-ng",
"method": "자체 작성 문장의 오프라인 포먼트 합성; 외부 녹음·네트워크 TTS 없음",
"files": [
{
"file": "intro.wav",
"text": "으하하하~~ 나는 에스다. 널 위한 행운의 단어를 불러주마, 잘 찾아보거라.",
"sha256": "4c271551d99cd9dffc01f35c176e98b54b4879549543ff8e2c79c6af8d4dc53a",
"bytes": 259900
},
{
"file": "luck-apple.wav",
"text": "오늘의 행운을 담은 단어는 ‘사과’입니다.",
"sha256": "51e6cf35b219f13c0d72ec9633f0c108c3393bc5ef6ae6aca6aa5d00153b4177",
"bytes": 125658
},
{
"file": "luck-sea.wav",
"text": "오늘의 행운을 담은 단어는 ‘바다’입니다.",
"sha256": "6585cb8d50eea173395417fc5fb357f55901665fe45dd07d942f79e202729111",
"bytes": 123366
},
{
"file": "luck-tree.wav",
"text": "오늘의 행운을 담은 단어는 ‘나무’입니다.",
"sha256": "6d188188d1478d0298536e0e03a58883629459dee56c6ae8ab88b4d7170c1def",
"bytes": 121224
},
{
"file": "luck-hat.wav",
"text": "오늘의 행운을 담은 단어는 ‘모자’입니다.",
"sha256": "be8d4287ebce15e221a8908f6b2d7478e789ecc51ba95d65fdf34f130954e7e5",
"bytes": 121644
},
{
"file": "luck-umbrella.wav",
"text": "오늘의 행운을 담은 단어는 ‘우산’입니다.",
"sha256": "188e24932e5e68fb0de8270e5b48128d486da956ad4069afbbcd0ad9af5913ce",
"bytes": 122178
},
{
"file": "luck-market.wav",
"text": "오늘의 행운을 담은 단어는 ‘시장’입니다.",
"sha256": "e58cdfd5a43074179e65edaf5f223dd15ad1accdd2fd547a6d3311de57b78eca",
"bytes": 124352
},
{
"file": "luck-oil.wav",
"text": "오늘의 행운을 담은 단어는 ‘기름’입니다.",
"sha256": "8b1070414191ff87b9531caf0782b13458b246a1f07b51f7ddcff2cd613930f7",
"bytes": 120286
},
{
"file": "luck-sound.wav",
"text": "오늘의 행운을 담은 단어는 ‘소리’입니다.",
"sha256": "052e2c2724c2fcf9d4c68ba3b746a430af0cfc74b42ed6f8317ae2cc5af1c2ad",
"bytes": 122660
},
{
"file": "luck-meat.wav",
"text": "오늘의 행운을 담은 단어는 ‘고기’입니다.",
"sha256": "dcf3d1c84a9ee00ea8a1ea5552ac69b3dc46b9c4160ee3375a4afe38426c0b8d",
"bytes": 121754
},
{
"file": "luck-furniture.wav",
"text": "오늘의 행운을 담은 단어는 ‘가구’입니다.",
"sha256": "6265e3807ea10eb82e9bb15a7e72dcab5e148277bc49bacfdb2663817d151ddf",
"bytes": 122164
},
{
"file": "password-apple.wav",
"text": "연습 암호는 ‘다과’, 진짜 암호는 ‘사과’입니다.",
"sha256": "14b7c8c0253784f319a04b568da594d8e46077d03931a36a23e8a7689dd4b928",
"bytes": 161688
},
{
"file": "password-sea.wav",
"text": "연습 암호는 ‘사다’, 진짜 암호는 ‘바다’입니다.",
"sha256": "832178b1eee4fe29653ca8dfda5bfb356cab83f4f880a704ee9eab937443f872",
"bytes": 160256
},
{
"file": "password-tree.wav",
"text": "연습 암호는 ‘나루’, 진짜 암호는 ‘나무’입니다.",
"sha256": "ef25aa09f89acadcbb2c43a1f18d0c2da292fae4d87d052868942d08b3825a8d",
"bytes": 156642
},
{
"file": "password-hat.wav",
"text": "연습 암호는 ‘포자’, 진짜 암호는 ‘모자’입니다.",
"sha256": "aef3f595e1b2d36212d4611f9998d841303e96ee5385639094aebcc984ff8a94",
"bytes": 158616
},
{
"file": "password-umbrella.wav",
"text": "연습 암호는 ‘부산’, 진짜 암호는 ‘우산’입니다.",
"sha256": "6bc1bf13c3fd1739bc9e490525ecd5839b9a4032faecb9f101a2c68824d57b82",
"bytes": 162668
},
{
"file": "password-market.wav",
"text": "연습 암호는 ‘지장’, 진짜 암호는 ‘시장’입니다.",
"sha256": "33036e08a06dd33b6aa86e5b78352d2f90e35ac1c7f9f202af2a32e2ceffcfc1",
"bytes": 166360
},
{
"file": "password-oil.wav",
"text": "연습 암호는 ‘이름’, 진짜 암호는 ‘기름’입니다.",
"sha256": "d88914ab7302112beecb6b2edbe114c3c119ee375985eca9716bf239aea94038",
"bytes": 157396
},
{
"file": "password-sound.wav",
"text": "연습 암호는 ‘오리’, 진짜 암호는 ‘소리’입니다.",
"sha256": "d3df570902e1f1fb5b2a7c573d57857bf4da547fb97ebdf27f04fbbf29c1170f",
"bytes": 155298
},
{
"file": "password-meat.wav",
"text": "연습 암호는 ‘보기’, 진짜 암호는 ‘고기’입니다.",
"sha256": "59c422dbf3c2ed7a397e7bf3455a2bf59132f85477765c6ec13673633cdb1e8c",
"bytes": 157754
},
{
"file": "password-furniture.wav",
"text": "연습 암호는 ‘하구’, 진짜 암호는 ‘가구’입니다.",
"sha256": "c349bd57598eec8543ce488dd86a4c4ddd4ec661ac9e8d7f42d914d545f38f61",
"bytes": 158998
},
{
"file": "remember-apple.wav",
"text": "‘다과’. 이 단어는 잊으세요. 이제 ‘사과’, 이 단어를 기억하세요.",
"sha256": "3123d84c546ff4e630a8b93d59bd5e668a5de30ea651e56e134d47690aead28b",
"bytes": 205094
},
{
"file": "remember-sea.wav",
"text": "‘사다’. 이 단어는 잊으세요. 이제 ‘바다’, 이 단어를 기억하세요.",
"sha256": "d802055500865e38b9beffe0213b70314aa59ec181cb1af1897dd010bb5875e3",
"bytes": 204654
},
{
"file": "remember-tree.wav",
"text": "‘나루’. 이 단어는 잊으세요. 이제 ‘나무’, 이 단어를 기억하세요.",
"sha256": "1e3f340609eb9844b7fc727f0c17a7f9f60245d4e00df2330d734efa97d26a33",
"bytes": 201206
},
{
"file": "remember-hat.wav",
"text": "‘포자’. 이 단어는 잊으세요. 이제 ‘모자’, 이 단어를 기억하세요.",
"sha256": "8a3cd1ef975d8a6782c018bbe23d9e69b4876fe8e64dcb9971f5025bb7072a4c",
"bytes": 202530
},
{
"file": "remember-umbrella.wav",
"text": "‘부산’. 이 단어는 잊으세요. 이제 ‘우산’, 이 단어를 기억하세요.",
"sha256": "5c5ab3c30f02d3a3b8188f1d81f4d8f617a9e9783c18da38bf6d4bee9d03709e",
"bytes": 209448
},
{
"file": "remember-market.wav",
"text": "‘지장’. 이 단어는 잊으세요. 이제 ‘시장’, 이 단어를 기억하세요.",
"sha256": "eb582873b55043a61b80e34b25302f8d52ae9c7d641032ce65ddca8fb9bfb181",
"bytes": 212988
},
{
"file": "remember-oil.wav",
"text": "‘이름’. 이 단어는 잊으세요. 이제 ‘기름’, 이 단어를 기억하세요.",
"sha256": "d56d8639bf462b1c341c07252666975ff6f3428de74f0bef886019fe0085be57",
"bytes": 204388
},
{
"file": "remember-sound.wav",
"text": "‘오리’. 이 단어는 잊으세요. 이제 ‘소리’, 이 단어를 기억하세요.",
"sha256": "c3d8e3e75086fd52a38806ea2122542d4fe495e381d4aa4c36e72277449451bf",
"bytes": 200100
},
{
"file": "remember-meat.wav",
"text": "‘보기’. 이 단어는 잊으세요. 이제 ‘고기’, 이 단어를 기억하세요.",
"sha256": "be4cc7dc1af803a23eb4319d076ecf4c5ab37b56913287f49c3b3c96eb4a75ce",
"bytes": 201730
},
{
"file": "remember-furniture.wav",
"text": "‘하구’. 이 단어는 잊으세요. 이제 ‘가구’, 이 단어를 기억하세요.",
"sha256": "acc3efbba9ef6bf53a3992a669946b6c58e90c9821e2fb5ef8e8c4a738f8bdf7",
"bytes": 202972
},
{
"file": "last-apple.wav",
"text": "세 단어 중 마지막을 고르세요. ‘다과’, ‘사고’, ‘사과’.",
"sha256": "5f583e9af9213cd5dc78abb68e5fcba3dbb7c65d7d8131a53210d8326e5cbb87",
"bytes": 187732
},
{
"file": "last-sea.wav",
"text": "세 단어 중 마지막을 고르세요. ‘사다’, ‘보다’, ‘바다’.",
"sha256": "21e589a6f7c262cca5533a8599a9d4fb257028a6e0c42732f6147209ad35ecb6",
"bytes": 190468
},
{
"file": "last-tree.wav",
"text": "세 단어 중 마지막을 고르세요. ‘나루’, ‘너무’, ‘나무’.",
"sha256": "915249a9860aa29c36149fc57b04057b2fa6ab9253fdfa1e0837236f84cb7aab",
"bytes": 186820
},
{
"file": "last-hat.wav",
"text": "세 단어 중 마지막을 고르세요. ‘포자’, ‘모조’, ‘모자’.",
"sha256": "0ce70943449ec5fb18c57d4ba7ea09a6e995f4bc991db07c70c9a846e16679a1",
"bytes": 189216
},
{
"file": "last-umbrella.wav",
"text": "세 단어 중 마지막을 고르세요. ‘부산’, ‘오산’, ‘우산’.",
"sha256": "8e5a3a57fc55a7deae5df5be5425a970b0a4926b74844f0f6fba74d882d8ea73",
"bytes": 192394
},
{
"file": "last-market.wav",
"text": "세 단어 중 마지막을 고르세요. ‘지장’, ‘사장’, ‘시장’.",
"sha256": "2419dbb03e18d3528a615b4977405699ab5285ea4b392e45164b625ebb5ff0db",
"bytes": 201286
},
{
"file": "last-oil.wav",
"text": "세 단어 중 마지막을 고르세요. ‘이름’, ‘거름’, ‘기름’.",
"sha256": "8a7108a6b23dddb5f2ae1c72edf6c488335ccd322acdb6d96a371e7613d47eb2",
"bytes": 191000
},
{
"file": "last-sound.wav",
"text": "세 단어 중 마지막을 고르세요. ‘오리’, ‘수리’, ‘소리’.",
"sha256": "c2b77970b477fd05671c833daaf2fb48aace796e1da54a1f9286fca0a8b7f484",
"bytes": 185296
},
{
"file": "last-meat.wav",
"text": "세 단어 중 마지막을 고르세요. ‘보기’, ‘고개’, ‘고기’.",
"sha256": "f1bbcef87d1b2fda6d36ecc484c62c6f1a4a182c12e2e0ac8bb58f494809ddf8",
"bytes": 185540
},
{
"file": "last-furniture.wav",
"text": "세 단어 중 마지막을 고르세요. ‘하구’, ‘가교’, ‘가구’.",
"sha256": "5e625527e69a3f9a9c508cb9da26252ab621949d7ae9ff41bdd9336627234de0",
"bytes": 185132
},
{
"file": "first-apple.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘사과’, ‘다과’, ‘사고’.",
"sha256": "d539d03875121570650cac2a2bf800cc67e0a72effaf755e02c870f9569e5028",
"bytes": 203904
},
{
"file": "first-sea.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘바다’, ‘사다’, ‘보다’.",
"sha256": "2d789349b36dab9bbe784e2fcb8412704f2dd15b22ad63937bad9948720aa5fb",
"bytes": 207002
},
{
"file": "first-tree.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘나무’, ‘나루’, ‘너무’.",
"sha256": "af4ad056b18af0d376a1df7dda3d7b8419e76cda6ffe57dd71054692aa653fd9",
"bytes": 203354
},
{
"file": "first-hat.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘모자’, ‘포자’, ‘모조’.",
"sha256": "e34fd5edff5323e45f8621a2adb79ed871d1ce671bd3ac8c4a49a8c703878811",
"bytes": 205388
},
{
"file": "first-umbrella.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘우산’, ‘부산’, ‘오산’.",
"sha256": "4be32c725583f1579b15be4bbe110b4ab42705221a63621125aa1aa98f7f061c",
"bytes": 210768
},
{
"file": "first-market.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘시장’, ‘지장’, ‘사장’.",
"sha256": "37925d65ce12429905a1b185824722a34af8d77b15eb7bec3b52665b5c1fbc7c",
"bytes": 217794
},
{
"file": "first-oil.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘기름’, ‘이름’, ‘거름’.",
"sha256": "0991123aee956c26ca658382102c9b6d0a164fbf2dea45f07a978d2cc1fc6b80",
"bytes": 205784
},
{
"file": "first-sound.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘소리’, ‘오리’, ‘수리’.",
"sha256": "5b3063285cddd8f46a2c2cbbee1ecc9b64ecdbd287df76df65dec854679ec884",
"bytes": 201840
},
{
"file": "first-meat.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘고기’, ‘보기’, ‘고개’.",
"sha256": "acf07b6db586616e67e2841a6f122120a5b0b18543047271bd5b8c55e33786e3",
"bytes": 201712
},
{
"file": "first-furniture.wav",
"text": "세 단어 중 첫 번째를 고르세요. ‘가구’, ‘하구’, ‘가교’.",
"sha256": "acba37fc2641c7073210855d294eb7c6e5f3328652c606186b1b0e569e2d0bf6",
"bytes": 203872
},
{
"file": "repeat-apple.wav",
"text": "두 번 들린 단어를 고르세요. ‘사과’, ‘다과’, ‘사과’, ‘사고’.",
"sha256": "5fcef242c63dc7e86c02a1a5813e409e6392511aad5834510696b0d0499a5ef1",
"bytes": 215994
},
{
"file": "repeat-sea.wav",
"text": "두 번 들린 단어를 고르세요. ‘바다’, ‘사다’, ‘바다’, ‘보다’.",
"sha256": "ef675bfa38f4eb4abac04cc64aa2c3ec416d405f9c67646356c9a8f39fe17d21",
"bytes": 211180
},
{
"file": "repeat-tree.wav",
"text": "두 번 들린 단어를 고르세요. ‘나무’, ‘나루’, ‘나무’, ‘너무’.",
"sha256": "b6a1d2923d90f9dd35b324aea419daf3891b76cc8c5c9551fe5ec1140c2ab0bf",
"bytes": 206504
},
{
"file": "repeat-hat.wav",
"text": "두 번 들린 단어를 고르세요. ‘모자’, ‘포자’, ‘모자’, ‘모조’.",
"sha256": "32cbc9823f5af5f897416bec2c377a8559c82fd3fae66273152826dd000cdc4c",
"bytes": 208872
},
{
"file": "repeat-umbrella.wav",
"text": "두 번 들린 단어를 고르세요. ‘우산’, ‘부산’, ‘우산’, ‘오산’.",
"sha256": "4830662f39bc0c62ee9be89de80a44a837c50063fad8fb63129b865673de5525",
"bytes": 220408
},
{
"file": "repeat-market.wav",
"text": "두 번 들린 단어를 고르세요. ‘시장’, ‘지장’, ‘시장’, ‘사장’.",
"sha256": "0e146387377dc38fc10435e06e8eb8cd30a595092887bf8ee4c9d0e7b577650d",
"bytes": 232742
},
{
"file": "repeat-oil.wav",
"text": "두 번 들린 단어를 고르세요. ‘기름’, ‘이름’, ‘기름’, ‘거름’.",
"sha256": "94de2ef7f7d7f9132f3646c3dc09399de23b81909f3edf4bbd1c5b01fad4d8fe",
"bytes": 216502
},
{
"file": "repeat-sound.wav",
"text": "두 번 들린 단어를 고르세요. ‘소리’, ‘오리’, ‘소리’, ‘수리’.",
"sha256": "7f12b6f49a7b4f64af796aa4ad8cfffc85a6b39e2bc6698f74b420b74af6c7c8",
"bytes": 205404
},
{
"file": "repeat-meat.wav",
"text": "두 번 들린 단어를 고르세요. ‘고기’, ‘보기’, ‘고기’, ‘고개’.",
"sha256": "ba8beeb33bcbe4771aaea9b3832a4c25868f6e34e37b3e3d026e891c07b8e71a",
"bytes": 203544
},
{
"file": "repeat-furniture.wav",
"text": "두 번 들린 단어를 고르세요. ‘가구’, ‘하구’, ‘가구’, ‘가교’.",
"sha256": "581a94726b08b6cfd3c688f08838a05787ed902ab6d1d4a038e0ff6b34f63c3a",
"bytes": 208274
},
{
"file": "correction-apple.wav",
"text": "정답은 ‘다과’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘사과’입니다.",
"sha256": "53d1c1b207607e610964e68134a3d35ff521b569e228366ec4eb7c03691724bb",
"bytes": 256484
},
{
"file": "correction-sea.wav",
"text": "정답은 ‘사다’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘바다’입니다.",
"sha256": "df61f91374b9fbb5817249ae3b6cadfae914d3e97ee2c6d07366ef82080a11db",
"bytes": 255204
},
{
"file": "correction-tree.wav",
"text": "정답은 ‘나루’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘나무’입니다.",
"sha256": "837c24b18f63a73e135511b2edd48ba12593317de3be4d225622e6d11b1a57da",
"bytes": 251316
},
{
"file": "correction-hat.wav",
"text": "정답은 ‘포자’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘모자’입니다.",
"sha256": "00d7c21caccbbb6c80ec6218415be1b0a6683a2d509b60821d3556e43353b5dc",
"bytes": 253208
},
{
"file": "correction-umbrella.wav",
"text": "정답은 ‘부산’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘우산’입니다.",
"sha256": "9bb3ce5b00ccc1632c37638550f329cbb6cda01864433e068f85eb7ccab86370",
"bytes": 255400
},
{
"file": "correction-market.wav",
"text": "정답은 ‘지장’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘시장’입니다.",
"sha256": "c8152db42c956701cd5e21c588ef62aedaefa922658d4bc0fecf8243548d7054",
"bytes": 257262
},
{
"file": "correction-oil.wav",
"text": "정답은 ‘이름’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘기름’입니다.",
"sha256": "228759e87b1c80be72ea34ff5b77cb5e4557afca1b73434ca8f6f1c2fedaa836",
"bytes": 247864
},
{
"file": "correction-sound.wav",
"text": "정답은 ‘오리’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘소리’입니다.",
"sha256": "24f2d52bb865c71fc4735a4aebd69ce0e429a9f68646e73e77adababbe34af93",
"bytes": 250170
},
{
"file": "correction-meat.wav",
"text": "정답은 ‘보기’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘고기’입니다.",
"sha256": "821caf897ddab107df8435b00b686bf9223e043c91a311edcaa0c3c5eb8c6511",
"bytes": 253432
},
{
"file": "correction-furniture.wav",
"text": "정답은 ‘하구’입니다. 아니, 잘못 말했어요. 정정한 답은 ‘가구’입니다.",
"sha256": "5d69426f3319fa435ee60b234540dd8d9a07f00900177f03da2770f44511ade8",
"bytes": 254342
},
{
"file": "middle-apple.wav",
"text": "세 단어 중 가운데를 고르세요. ‘다과’, ‘사과’, ‘사고’.",
"sha256": "0ecc7a7d27508f73c9064a35609c922bbdd6fce8ebfc155e74f7b78d4e897dae",
"bytes": 191056
},
{
"file": "middle-sea.wav",
"text": "세 단어 중 가운데를 고르세요. ‘사다’, ‘바다’, ‘보다’.",
"sha256": "c7828af4e64745d89a6f23fda6c86efb76febe379bab0901c2972a4569947604",
"bytes": 194176
},
{
"file": "middle-tree.wav",
"text": "세 단어 중 가운데를 고르세요. ‘나루’, ‘나무’, ‘너무’.",
"sha256": "756d13453c7e13dcfaa65c8cb3497ac8d3a5d12bedb56dcd74e7f1c022392416",
"bytes": 190516
},
{
"file": "middle-hat.wav",
"text": "세 단어 중 가운데를 고르세요. ‘포자’, ‘모자’, ‘모조’.",
"sha256": "6ad5ec1e2c2c0de568c55a0c1f0e8361885725a2515cf396c8fe5d2106ae22d0",
"bytes": 192548
},
{
"file": "middle-umbrella.wav",
"text": "세 단어 중 가운데를 고르세요. ‘부산’, ‘우산’, ‘오산’.",
"sha256": "a507896dd50f98909c6a9fc0a4bfddfde5c975836e494cd9b7f40b69bc8ec33b",
"bytes": 196102
},
{
"file": "middle-market.wav",
"text": "세 단어 중 가운데를 고르세요. ‘지장’, ‘시장’, ‘사장’.",
"sha256": "900024616e512ea6777d08f80e3e2c83815ea1f03b6eeb537d212995474e1048",
"bytes": 204956
},
{
"file": "middle-oil.wav",
"text": "세 단어 중 가운데를 고르세요. ‘이름’, ‘기름’, ‘거름’.",
"sha256": "c42389a5ccd3b39a5877a38e647a6abbec6ff6a7eabf3d4c95c0507fa65d6d2f",
"bytes": 194772
},
{
"file": "middle-sound.wav",
"text": "세 단어 중 가운데를 고르세요. ‘오리’, ‘소리’, ‘수리’.",
"sha256": "b05ae2042bc973c3d1873fe15b5bc7f2af7e803794315023486efa788048342c",
"bytes": 188984
},
{
"file": "middle-meat.wav",
"text": "세 단어 중 가운데를 고르세요. ‘보기’, ‘고기’, ‘고개’.",
"sha256": "d54d6f9b4bd90b840443b9e0b0390a93909eeb81c37af6a9b57ce545bede532d",
"bytes": 188870
},
{
"file": "middle-furniture.wav",
"text": "세 단어 중 가운데를 고르세요. ‘하구’, ‘가구’, ‘가교’.",
"sha256": "d9318ef33ae1c60630ddda5abeefcbe43626d8f8a9abd5d62efd132eeb77c8fc",
"bytes": 191024
},
{
"file": "message-apple.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘다과’, ‘사과’. 지금은 빨간 불입니다.",
"sha256": "3867563d5acd2530c72cbe6f98ca2b463ec0c92285069c99c8ba084c45aabfd6",
"bytes": 316834
},
{
"file": "message-sea.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘사다’, ‘바다’. 지금은 빨간 불입니다.",
"sha256": "b7d8d89d93247eca9aec124f80bf6328d6d88511d05b513ce6d9fa32b3211848",
"bytes": 317816
},
{
"file": "message-tree.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘나루’, ‘나무’. 지금은 빨간 불입니다.",
"sha256": "9539e5ee87068e241598db2e4fbacb240daa011a2238c9864da8ffde6b644918",
"bytes": 315930
},
{
"file": "message-hat.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘포자’, ‘모자’. 지금은 빨간 불입니다.",
"sha256": "ccbba6a22c9cbc1231f45fbd7420c6257ac22ac72de8e8c0c97f1cc31bb2b16e",
"bytes": 317258
},
{
"file": "message-umbrella.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘부산’, ‘우산’. 지금은 빨간 불입니다.",
"sha256": "e980f4476f7275cc5ae24e7ce0e6d9c1e6db027f7cbd1eb39cc5bc4bc07cbf6e",
"bytes": 320532
},
{
"file": "message-market.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘지장’, ‘시장’. 지금은 빨간 불입니다.",
"sha256": "35432a3ed8dd1e15894ace5aad6f5a66cf28509ba92b8ee47bcaae424cb25ba1",
"bytes": 325564
},
{
"file": "message-oil.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘이름’, ‘기름’. 지금은 빨간 불입니다.",
"sha256": "814fc749006ed040de58b5236a8d92f0d79683c8eea3b9d095386344f41a47bd",
"bytes": 317786
},
{
"file": "message-sound.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘오리’, ‘소리’. 지금은 빨간 불입니다.",
"sha256": "e25c867e6c18d906c010816475253d2b10aa3cc4192b5551ba78055d65c461c8",
"bytes": 313270
},
{
"file": "message-meat.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘보기’, ‘고기’. 지금은 빨간 불입니다.",
"sha256": "f1863e1527b7714ae64f5d752b542e8768b8ed89b5885012283f7ca20742ee00",
"bytes": 314464
},
{
"file": "message-furniture.wav",
"text": "초록 불이면 앞 단어, 빨간 불이면 뒤 단어입니다. ‘하구’, ‘가구’. 지금은 빨간 불입니다.",
"sha256": "43f87d0e3d92bd132f9ea46e024b9a940736b7399e899866ed42af367a550f78",
"bytes": 316152
},
{
"file": "mission-apple.wav",
"text": "오른쪽 표지는 ‘사과’, 왼쪽 표지는 ‘다과’입니다.",
"sha256": "36697151a1a57645f5acd9fcca2d13bffa21937e1bbcde08ab2d8d485730145a",
"bytes": 166540
},
{
"file": "mission-sea.wav",
"text": "오른쪽 표지는 ‘바다’, 왼쪽 표지는 ‘사다’입니다.",
"sha256": "2741f404e39ec64af7f73452f82c68b3ae1d377e9f40a586034f9b147fbfb114",
"bytes": 165122
},
{
"file": "mission-tree.wav",
"text": "오른쪽 표지는 ‘나무’, 왼쪽 표지는 ‘나루’입니다.",
"sha256": "8a7bb2c795d8877433be2621b69a48c2b6c5c1e192c094c01257fb93eb5d9449",
"bytes": 160834
},
{
"file": "mission-hat.wav",
"text": "오른쪽 표지는 ‘모자’, 왼쪽 표지는 ‘포자’입니다.",
"sha256": "26dfa26bd8dcb9d63c231dfc37bf25970f4a8dadcaa40347dd15974887e948b1",
"bytes": 163102
},
{
"file": "mission-umbrella.wav",
"text": "오른쪽 표지는 ‘우산’, 왼쪽 표지는 ‘부산’입니다.",
"sha256": "79be98918c3fb4e5e4e2e51b2bfa5e5aad6c600478ae1a34c055b16ce71d5264",
"bytes": 167480
},
{
"file": "mission-market.wav",
"text": "오른쪽 표지는 ‘시장’, 왼쪽 표지는 ‘지장’입니다.",
"sha256": "8f18144a91072be37dc31a161fe6e9bb1980ab36af0edee8d7a359397b8bb8ac",
"bytes": 170724
},
{
"file": "mission-oil.wav",
"text": "오른쪽 표지는 ‘기름’, 왼쪽 표지는 ‘이름’입니다.",
"sha256": "1ceabc58f445f7bd5609b2f9de80b309ad64d11c888c7261cf84315a7637a748",
"bytes": 161758
},
{
"file": "mission-sound.wav",
"text": "오른쪽 표지는 ‘소리’, 왼쪽 표지는 ‘오리’입니다.",
"sha256": "6651b14caf4e54069730f137e5d8c3c1e5a9c66aa72f15623cc442edb967cadb",
"bytes": 160162
},
{
"file": "mission-meat.wav",
"text": "오른쪽 표지는 ‘고기’, 왼쪽 표지는 ‘보기’입니다.",
"sha256": "5d2ab3071fd27e850d99c50ad37905096ef28267b660a35992559bdc126c4931",
"bytes": 162626
},
{
"file": "mission-furniture.wav",
"text": "오른쪽 표지는 ‘가구’, 왼쪽 표지는 ‘하구’입니다.",
"sha256": "080307bb46bb47378c0c03437d9ef44118a5d4ea17b2b6d70e5cbc710c71ba78",
"bytes": 163884
}
]
},
"head": "1c0069c367f6e108d3f67a2a0d044399dd0ef2bd",
"branch": "fix/v0.1.1-neural-voice"
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,259 @@
{
"head": "a92b2ba1e973c65a57e6e34cc52568cd6b208c1e",
"files": {
".agent/evidence/01-content-green.log": "5585acd257b49225218835acd69a1d240c7737d12dba62949f31a5b7c1c9ed2a",
".agent/evidence/01-content-red.log": "0f28fe2ae2c4669a52ba2fc15bfa6285e4922474dc2b2571098b522679948e12",
".agent/evidence/02-game-green.log": "5ca5895f8a09f4e9de7a846bf9ab37fb3715623e8e7654dab095505c097fc0c7",
".agent/evidence/02-game-red.log": "78468ee5c25c1685f3613926f636b6fb4569227533feda3547afc6b8123d6452",
".agent/evidence/03-dsp-green.log": "d3d08683a1426b845a2e987572861b82b3ac978b8c352991950c0f32a473d3de",
".agent/evidence/03-dsp-intermediate.log": "084a52294f718718256eb1516048a672d045a5f7dcb5d11c646092d29efbab58",
".agent/evidence/03-dsp-red.log": "bacf42e5c808d32702b9bcd30523d1fcf17d5ff75b281233d9e84f33b6e42589",
".agent/evidence/04-audio-green.log": "d48c93fa7d32315ed4f719dee19222e7398bc4c4bceb8cf345e0e221a9ac89d8",
".agent/evidence/04-audio-red.log": "58bbf8eae572f83e408dd101eac738a5f6963550e21c8265f42a7eeba18be7a7",
".agent/evidence/05-assets-red.log": "04388acb098f7dabe9a35783b496075ee7c39757d3fde5361c9ac080188ac371",
".agent/evidence/06-ui-05-assets-green.log": "ced2ad738cda673b24308dcb9d99d59e3ae918709eeb32de359d6ab1022133e2",
".agent/evidence/06-ui-intermediate.log": "3295b3ae691dadb8feb7f0aaf604a1aa56cbfae27b5dbdd486cb5645f5edabe9",
".agent/evidence/06-ui-red.log": "1f1ed6bd440af22f5abf59e4be194f969bee1d115d436a155d879d8cffddb747",
".agent/evidence/07-build-green.log": "ec98087d20a68c5b81c6c23406316f1e5f19c6124498e1fc005d04bb78894a57",
".agent/evidence/07-build-red.log": "138802de7bc67c1535668efe7a915424a70d5d7994acb7f366a139e89c1da77f",
".agent/evidence/08-rule-green.log": "91b7ce3fda181fbe51cbe4e6debb61dd44dd55226dcfa81ed73559ba76811f3f",
".agent/evidence/08-rule-red.log": "2cc1854cf6a4b9e8d53a7a36b1dde1fb6c6970b89f841b9e8f404e6e42bb929e",
".agent/evidence/09-ime-green.log": "e5d5d1cfa2b6db724ded97d5f3309a517bcf637d9b2b417e9110dc9da0a48d72",
".agent/evidence/09-ime-red.log": "10e5f9f99609044c768cd338df0d574a06a7442e0debe0e61ca16a6b5873adf3",
".agent/evidence/10-ime-reset-green.log": "e12761b3a2814a79d1448e7452474a086bf371921287718eb72dd9b0f6b8fc82",
".agent/evidence/10-ime-reset-red.log": "f6cb7c1724b8f9c410385e9970051577c03527fb7e719f43a77c967ca08ef18f",
".agent/evidence/11-provenance-green.log": "54dcc417b97f82422c5c3e0ae11caa1f15a60412853ea1dc0152d15031bcd935",
".agent/evidence/11-provenance-red.log": "e69fa7989223e659c16b8030f8668e562ad5b0daa060fbb1c9eff41a37fd56fd",
".agent/evidence/12-ime-replay-green.log": "a93d9f16c7d81ed5e9a7c0b70ffee1e393d2943ddf3149a5bb115c5517327c44",
".agent/evidence/12-ime-replay-red.log": "8cf5dab06d93cc544c21276ee633829f8b137b4b6d7c5fe47aadcad6fc2afb71",
".agent/evidence/13-heading-build-after.log": "19829ac264f97aa023baf7d5e1fd429343272f3bd952e8b6dfb9eec0f594b453",
".agent/evidence/13-heading-build-before.log": "646d197d2ef93c19fec4719e20297de1b22eff54f3e6155ba2125fd3dd372c46",
".agent/evidence/13-heading-green.log": "d59fa8546083e9d371c7a552287f27bf3acd572bd0cce3da8eba860da5c05880",
".agent/evidence/13-heading-red.log": "33acc2838786a87b8ecc170a1ac0a9d7521daf8e5b9aed2195e76e45ea327f76",
".agent/evidence/14-snr-browser-green.log": "fcb82296e9af4b96112fae0bbb77c6ba41230c117021243e85916ae1130a462d",
".agent/evidence/14-snr-browser-red.log": "36298e5bb1f45a69b0ca75e5cbce85ee1455c4485759670268fbbcf55bacd4d4",
".agent/evidence/14-snr-build.log": "1e9ce36a48904a58195f9d1c2d9ca6cf2895fcb8bd0b5ab9b72f76e92c6b2585",
".agent/evidence/14-snr-green.log": "ae74e57cea20841299a8c1ee5eaf60efad34bda697339f45527cdec83578e6df",
".agent/evidence/14-snr-red.log": "b39bdbd8815d0d9cfcedc41c61124afece2011ea6c6c250b0ee0139eae7e9edd",
".agent/evidence/15-volume-browser-green.log": "aeccd5f13eb9db4062cbf2c70eee332d0c39540d580e113d0a79a899b2ef02de",
".agent/evidence/15-volume-browser-red.log": "84954280c1729703f9e9c2680c8933c3b0752b19fb9c3562e7dbf2ea1b4a548c",
".agent/evidence/15-volume-build.log": "2767b794124804b3447f529eef025e2530975fcc506e1cbe8994acf8243e6ba8",
".agent/evidence/15-volume-green.log": "0f9a90923f4fdc477c8f2436653eb2bf0e4b251bcb52e795701309ba14f23c7d",
".agent/evidence/15-volume-red.log": "9beae6305080cd0d869bf3fd2093beb6e2e25e5424223aa7e4ad4db96954f37e",
".agent/evidence/16-copy-green.log": "dacbdbab5d4af2b6e19eb4e0502a70720aac9fb6cf3b9d6dfdc73a5bf7edabfe",
".agent/evidence/16-copy-red.log": "ebe3d7c86938d33d7f1a4818b18c7e94ab8feb18bee099fcb535a93d8083861b",
".agent/evidence/17-spacing-green.log": "8ab85362ceadcdfecf4f7b1e95abfb4237e15018692e14f937be90265c351b11",
".agent/evidence/17-spacing-red.log": "12db8083cd8627a81a52cd32358780a3c2257cb3bd702350b190b39226f6550f",
".agent/evidence/18-literal-green.log": "878a8d788a8cedbf652fe0e819fe482099249a52ae7b5cc3d8826e64b32c6377",
".agent/evidence/18-literal-red.log": "ad23ae7be3d9aab83907c12849012a01f9d1b12e5a174c3acede89817a74d2d2",
".agent/evidence/19-notices-green.log": "efc51aca0738f3cb5264ec3c3ad0d17bb150d685f5fdb5e200bc1eedc0e3c02b",
".agent/evidence/19-notices-red.log": "8f34c583cb8563803828d72fe56622d84bcf59a9541d983d6c0b705225955794",
".agent/evidence/20-audio-generate.log": "f864fc266f7ca50c600457399f198a77949e9ee1601b0d2fc19b64942a2030cb",
".agent/evidence/20-audio-green.log": "edb9b9f0aa1af11835960eee9bb6e8c013341aa528d2857bac0b89ac38457528",
".agent/evidence/20-audio-red.log": "c1cbd5b585e8a70e23b88bfcee0c6479f85fdec0d1e06d13c81c689a140c0ac0",
".agent/evidence/20-mechanics-green.log": "9776c68143f668e35df8b2e19884b25d2369e4800b4c264e635d0c260818c5f1",
".agent/evidence/20-mechanics-red.log": "d25a1c844366e14fe1db9bb7c243fe0adb6857ee5b4548cf2865de96589af647",
".agent/evidence/21-node-green.log": "3c36e9e45b6844ae2c184f943b61195482d9de53ceab06221093c8281d210d73",
".agent/evidence/21-node-red.log": "ee25556037bdbd6b099dbb087a522284e8df00bd573dfcf0e42c734e31e09e84",
".agent/evidence/22-sandbox-green.log": "e8a1a17e49c22dea81d7f85111c744473427466791ddeda75047cd0082e7faba",
".agent/evidence/22-sandbox-red.log": "c8a97270f0f68367d6edb3e5ee10f34bbda1127f8dae2c5639afd482198e7bcd",
".agent/evidence/23-delivery-browser-red.log": "180a61bbacf85db9e52f721b50da683103b719bc350454cc99d4c8954b2ae86e",
".agent/evidence/24-retry-audio-budget.log": "b9241872b4ecd80265df4c6c2be90b31e9de4d0754772655e50b7fb4f05e2d3b",
".agent/evidence/24-retry-final-browser.log": "68029aae89adf86fd60ee56a20a1e2f769cb4f894f27ae23963ca5b5b58c62c4",
".agent/evidence/24-retry-final-build.log": "702c20554872e437137097ca59a80d911188477f018bc48c4b49a770b73d5a84",
".agent/evidence/24-retry-final-lint.log": "8682ca1f55e3ec58f13321cc339c8647ef72c1934d74ea9b980aee717e528819",
".agent/evidence/24-retry-final-test.log": "b71bb1375a039bcc3d7b3c5070da85ece3551f32ae1b8bb3a2abc5ef1edd57b8",
".agent/evidence/24-retry-integrity.log": "a188fe54dce05f6caa868b3d9f2c22a852f6a8cdc462355673316578be623a08",
".agent/evidence/24-retry-targeted-green.log": "4e53f2de988040540f5075b2e4a483ca53b671486c35e864fbc3c2c9c5361c61",
".agent/evidence/audio-reproduce.log": "5f5726f3ed6845882c7a6d6f9a8d898c2b73bf61fa6328e8bbafd25f61ed4268",
".agent/evidence/browser-final.log": "9273c91613160e239027452894b3735f9657ccad97a52412eb889290aebd5adf",
".agent/evidence/browser-first.log": "f3087028d76aae36d61d7a14da488bd809079a9e121a2d8fb01fa034f99d4f05",
".agent/evidence/browser-second.log": "2ff1d16f51b9384cf431d5923ad87d773510fe4b89bdf62f09cbda2efae20e3b",
".agent/evidence/browser-third.log": "1b6c264930da8934e7f1c8da6c998543f35e68b1c3159dad722cfe23a8e5244c",
".agent/evidence/changed-files.txt": "2b609231e5c7becd581f79413a4f7443312e71f0099ac6a51b2c5f0dfdee576f",
".agent/evidence/desktop-game.png": "42702e89264357257db8bf54c2b3743e3212e62cfd3476a8c25bad83fb59ff81",
".agent/evidence/desktop-home.png": "bf2f515fcd483cd5ca9a3b408f484d3556b75b1be0bb70360b7fd5f7c3404993",
".agent/evidence/desktop-results.png": "003df3aeb08ce66618775377d9b2003809d696629f61cf54b7b86e7a0ed63593",
".agent/evidence/final-audit.log": "6d8c5c8f3d7684adb070417bd608d01ae90aa3dc26a65af03ffda4955f38d9a3",
".agent/evidence/final-browser.log": "5855691def462b23667a9d658338a0458a53d984b5b5f7e11b45f9a63092abcd",
".agent/evidence/final-build.log": "565a95a51a10f78bc08f256755afce5ef183440dcdea5e75b3aefde8d7c5b837",
".agent/evidence/final-lint.log": "d2354c241320f11f07890cbf32f99a5d88f1c7f4f236d860e2cd26db739badd8",
".agent/evidence/final-security.log": "c585566624a4596e97327fb1864b1ac2a3189c0794b1e25a9d6ff1abb86046cb",
".agent/evidence/final-test.log": "af03027cb22a090ecd107c10e3fc7e2f9ceb394122b0b73caa7d362310504170",
".agent/evidence/mobile-game.png": "20a3f02f70a28b2faae1b33d0d4d6fea10b77caa426e4bf9faa5ef6d4474a846",
".agent/evidence/mobile-home.png": "7f84bd54183fcdd03fe136b41145146ddfb323041c96a8b9e6b670c9a923033a",
".agent/evidence/mobile-results.png": "ec2938c03ac03da8e33e25f043522b317b60c16be1c29f9dd325a81ae84513a8",
".agent/evidence/neo-before-spacing-browser.log": "e5c214f14bd93ef1bb731f87ecfd3a02d299c9f9e5a788233f6eda5eb8946b4f",
".agent/evidence/neo-desktop-game.png": "f5966688ba46f14fab5125452f935e55f6e6dc4355c876416729866129daea70",
".agent/evidence/neo-desktop-heading.png": "db609f2f54af0e6b1bb96bce9bf839454403d6e2787e6520a2928fad31beb021",
".agent/evidence/neo-desktop-home.png": "826c5da794c4ea3c15bd6c13e81d1c021fbeb8a902fc4908b78f9c457f091c0f",
".agent/evidence/neo-desktop-results.png": "98a68ca050a4e66c17dcc3f1bd5f0e86bfc88c2ebe9a75284766d17e10426632",
".agent/evidence/neo-final-browser.log": "582e7cbb643201e4b197b566b021322448abaae0b383967ad0e816d0c351e96b",
".agent/evidence/neo-final-build.log": "f30138e53b8c12e70e80e2cd5f4bdfcf8d1f6a095216a4f9ade6687bca1f0488",
".agent/evidence/neo-final-lint.log": "d2354c241320f11f07890cbf32f99a5d88f1c7f4f236d860e2cd26db739badd8",
".agent/evidence/neo-final-test.log": "f718e2acda255fcba67b272c7fa625af450714b384bb67a72f09328bf6964f0b",
".agent/evidence/neo-intermediate-build.log": "9d8a1f0586d58196e03e45330b6e8ff5522fdd3c27870aae2fb052199f8cf5cb",
".agent/evidence/neo-intermediate-lint.log": "5e94ea847c3a092f4ff8e97ac5b61ebef805b3c859ad38461f4a437045d1b5b9",
".agent/evidence/neo-mobile-game.png": "1a6733a3293204e4841ec8722a1ffe37033943097c691bcfadbcd907fde024ef",
".agent/evidence/neo-mobile-heading.png": "ae07d0a1cb6f835525c7e0ef31655a543eaa9e10183596c2d409dead6faccf15",
".agent/evidence/neo-mobile-home.png": "9b3ba8b0a9f7b321882429e31ac4a0472fcc13a998dfadfc930c273bc37558d4",
".agent/evidence/neo-mobile-results.png": "d49fdf6ae9566d7a2003db3f252d84ed88ac4d73a0390ce404b47e7bab9c60df",
".agent/evidence/release-desktop-game.png": "7300a06a507f651a587ed3deb36cc5bb728f4a36c30b7b1cf409a3b209ba564c",
".agent/evidence/release-desktop-heading.png": "de454d77e29737e23c573646404489d5682004521deabfa01b439d607faa32ca",
".agent/evidence/release-desktop-home.png": "f28f744e11b66373ee8db6eda2f7bdc384da4f7e763fbb467a4cda30090e869b",
".agent/evidence/release-desktop-results.png": "2ebb4056d0ecdadea8a3469500801065ae158c17cd2db27817e813e53adc71f3",
".agent/evidence/release-docs-final.log": "3529acce5befee536ec7d8e9d22cbbf27182297bb07408ab6e31551aaee76ed3",
".agent/evidence/release-final-audit.log": "6d8c5c8f3d7684adb070417bd608d01ae90aa3dc26a65af03ffda4955f38d9a3",
".agent/evidence/release-final-browser.log": "2a9881cef8c379f41abf5d69dd5ad21881988f78c0579c95e463121dc37f6e09",
".agent/evidence/release-final-build.log": "3fba8356382341db9c562d985ca2229fd0b81969532746b0146bc489d54c321e",
".agent/evidence/release-final-lint.log": "d2354c241320f11f07890cbf32f99a5d88f1c7f4f236d860e2cd26db739badd8",
".agent/evidence/release-final-test.log": "46d5d0fc0180adc00a734b64db4acb4cbaa37d12567d0224836306312213870c",
".agent/evidence/release-format.log": "57658c36cb3161b53cdf934017e4b7a733a273509ace184e0a2a6eaa046c742b",
".agent/evidence/release-integrity.log": "cc77121b43a6b24a358999cf1a3bbf701d467fcee9730095f318303c2e80602b",
".agent/evidence/release-intermediate-lint.log": "ee597e984ebdf11ea247c8cb1551cda446580cbd7a3dc708f85fa78bb72700ad",
".agent/evidence/release-mobile-game.png": "83a918e5ff2142e540cd12b85806b3e69a71bc66df5d241f4b2f5abdaf493f82",
".agent/evidence/release-mobile-heading.png": "d5c92a3b62f749d5f064af12efa5a1a2ad13b177270ec01dd10a549a8437899d",
".agent/evidence/release-mobile-home.png": "c7fc37a247bbadba60de9dff3c8d87930a2e6ebb868f687a4135b3fd035ed1c3",
".agent/evidence/release-mobile-results.png": "587956c9ad5eca054e4bb4b44748a2c637655e407427ba5b4c6ad7bf5a74539a",
".agent/evidence-v0.1.1/00-audio-venv.log": "365f1b3cf48e7f6de9c24d28e4326a245d3a54eb329af4b41a9441ec546dabdc",
".agent/evidence-v0.1.1/00-npm-ci.log": "14a6e676c84fa9b2cc39a251aef0c593cda9903f9e5f2d9581bc4153c9f69e09",
".agent/evidence-v0.1.1/01-version-docs-red.log": "edb26b949d0dc28340989601e781df3582cf784220235d19c16a46aeee97d302",
".agent/evidence-v0.1.1/02-assets-red.log": "ccb8a354e2975c944fb2bde24492fe06a6c1b71add6ce65259d840c66836a1db",
".agent/evidence-v0.1.1/03-generator-red.log": "d78b7c9237c18ba8a87a77a116ea7561ae79af6e88718f9c087c1d8e2c70b1f1",
".agent/evidence-v0.1.1/04-generator-additional-red.log": "9a519598915fbdd98108ee1b364f634905e29a5a01bfdd7ffec22a8b359e9217",
".agent/evidence-v0.1.1/05-generator-green.log": "414464526a325b424e5c5305e3066b79c55527fb67b11a3b9eb3bb33dcecea93",
".agent/evidence-v0.1.1/06-audio-generate.log": "7b605184e89fd033378e6869236553a3d6e040087de23e8ae165f1e304f3b067",
".agent/evidence-v0.1.1/07-format.log": "ce1a102d13a7dfd78130216cea192e3230efa3612e999cb8a6bfd55e8eb6d471",
".agent/evidence-v0.1.1/08-version-docs-green.log": "671c2889a69c83ad24293d8e92d0076255bd00c5100c2a9eb764a570e1344edd",
".agent/evidence-v0.1.1/09-lint.log": "43d5238bc8e59b93cf3a9bc0f444f0165697b5584078973bd92efce056136c1e",
".agent/evidence-v0.1.1/10-audit.log": "6d8c5c8f3d7684adb070417bd608d01ae90aa3dc26a65af03ffda4955f38d9a3",
".agent/evidence-v0.1.1/11-full-test.log": "65721fcf2b03f153274c9cc1da13c6a1f265ab6f084be8b5921a898fbfd6b40b",
".agent/evidence-v0.1.1/12-independent-audio.log": "5ffd6173941d75deb028741cdba549705b652218f418c6d40ceb7f4b216f2d9d",
".agent/evidence-v0.1.1/13-build.log": "42ac41188359699f5f24c7f86de9d7ca6503d714a7be9e277ac2fd01be21614c",
".agent/evidence-v0.1.1/14-browser.log": "657ddc9f60ffa35684110766b2e459842cd1ab10a90b0002256a945f227a16b7",
".agent/evidence-v0.1.1/15-browser-audio.log": "cb16ec7009a88f911632d0bef64692066873d81372e65fea8dac800d59304214",
".agent/evidence-v0.1.1/16-final-lint.log": "43d5238bc8e59b93cf3a9bc0f444f0165697b5584078973bd92efce056136c1e",
".agent/evidence-v0.1.1/17-security-history.json": "5ba66683c3ae29e01f25cfae2ed832e33b07f866bfccd0e1d331a8f102d3d3c7",
".agent/evidence-v0.1.1/18-environment.log": "19a1da4298ba5a51f8dce5e6669205987bb48438e5c98f3ddcbc347ce0f91e46",
".agent/evidence-v0.1.1/19-final-integrity.json": "38f5af8927d95e9dae780decf146eb3d5feb610629202ef9ee67bf223647132f",
".agent/evidence-v0.1.1/audio-integrity.json": "d82b192602b1f054fce5f61479832666f237d7da2698afe84b09186dac90f321",
".agent/evidence-v0.1.1/baseline.json": "085be97acb81dcc83477ebc5f42dd2fd5729d9f5821cbc659df9c00b648ceb34",
".agent/evidence-v0.1.1/browser-audio-integrity.json": "2c0f59ed178285c0d338171328232351aab2b55e22371b3652453afa34849b65",
".agent/evidence-v0.1.1/changed-files.txt": "4877f3d1003372868b5a9f72326ccf0870b22daf35a71b60b67dc761342fa50f",
".agent/evidence-v0.1.1/desktop-game.png": "02c59fa37c4d4f19e5c74e56fc889105b4d280a0a4cf2c14c1838947859a3a8b",
".agent/evidence-v0.1.1/desktop-heading.png": "920d3d998d93f463be9ac6a682c1f7d5d9ac36944b52b715345c865ae46f566d",
".agent/evidence-v0.1.1/desktop-home.png": "9c6f92b67db249b2a1d3e752052678d7ae0af6be426d976d12237d84c105bf76",
".agent/evidence-v0.1.1/desktop-results.png": "3811eae6f5827760499c9c64053a2cb2ecbb1d87ed2ddf11b757eb44e56c64bd",
".agent/evidence-v0.1.1/mobile-game.png": "bb0dec7ec2c99b55caafd729e2f9c9c01875e3b6dd577cc377a76bbfd5c95a7e",
".agent/evidence-v0.1.1/mobile-heading.png": "d61f2d1b01c654a5cfe841e49e244af4e232b5fc9c899e77523b336411e99316",
".agent/evidence-v0.1.1/mobile-home.png": "7c4a4643a5222f45c6492ebf78780a317e26d423bf244fc16ea24a186a76f506",
".agent/evidence-v0.1.1/mobile-results.png": "f2a095ab1d2a3a95a1a275b652fcd31275a5803a926e01b5fcd1e9a9e127cfb9",
".agent/evidence-v0.1.1/verify_audio.py": "7751c03b83dbbd3b222f6d5a68eb1d78dac2bbf82c0fd79345ccca86a15fcb69",
".agent/evidence-v0.1.1/verify_browser.mjs": "53f0f6317274a91017a4f508ef9237e022f7d333ef4243f324720f8d7f85abeb",
"public/audio/correction-apple.wav": "ccd7327a3fb54d3320d049ffdced3bc17595861cee69429c0ee97182d454195b",
"public/audio/correction-furniture.wav": "5c004a7b2f5a4a918c9f689f1a2dcb219a620ed14313f40a9655b36dbf64948d",
"public/audio/correction-hat.wav": "f9f98c91cfbcfcb106eef7d5d3795a9cf3c3aab7e19a60f13d7dffe284d19f86",
"public/audio/correction-market.wav": "b8d25b867497adcd0fe7c8b6a8a8d2e7a52965956738a83e53f58735708773f9",
"public/audio/correction-meat.wav": "48e91b3932d3798e852041a854b3ee08c72127e092c62083a47af6b99adff241",
"public/audio/correction-oil.wav": "f6eff0cdddcad9790351491e60c53cb2a70d222033a583652f2de0b8cd6abcc7",
"public/audio/correction-sea.wav": "9233431d78ab4b144e3c33ad0cf0d49fc0fb91b29514343230ba32987b794bb3",
"public/audio/correction-sound.wav": "5a603bc69979603afddcaeb6edf500a7c540b72405daeb33f5335d746b327da1",
"public/audio/correction-tree.wav": "b8e8bbe6b8b14727efd953fae9d4aed2caeb004055d52f611c6378322847edbe",
"public/audio/correction-umbrella.wav": "92b54f04884ab915783945077efd8f3bd443849a1720f72168b6348cae1f8e85",
"public/audio/first-apple.wav": "7c1dbcb3082055df2b8f087f7e906ec867c92f679de0894c34740c05e61a4bc1",
"public/audio/first-furniture.wav": "29f007b385b7182db1d8aeccad4fc3c260df5e66e14e52a46b0ef0fcd0ff3a0a",
"public/audio/first-hat.wav": "17c8cde90567e7574b0c0702663bd70713054089ee920241b5444d9b7869eef5",
"public/audio/first-market.wav": "1e00b8f70a796cdebb0feb00c605fece7488b06915e6e036f54206f05e201e0c",
"public/audio/first-meat.wav": "f51a37c1722fef581f7d642a4dcae7fcb9953b3c318dce971bf616cd1a81fecc",
"public/audio/first-oil.wav": "f415195e0cfc7ee711d09de7519e88eab62cc8b58d70772c83c3f5c27c267819",
"public/audio/first-sea.wav": "0f0b39314c5f7d7168d4854003c0c284e7bc3438cdc4d1d1c5adab7cb5ed30e5",
"public/audio/first-sound.wav": "46f6adeed928a16af0700f1e8626cf8049f124632a04a5d10604426fb06f9596",
"public/audio/first-tree.wav": "3178230fd5850b6277a2153b438ec5289720e3db7ac929914cc213964f004bd5",
"public/audio/first-umbrella.wav": "878e0bd2e6e4105f175aef51a028f6b141f3a2072be20f783193f3ba897a3ee0",
"public/audio/intro.wav": "90d9f46e6e3f9c8a0c1a781096df54d7809ef4ad38b289508ef7b8c0411465ce",
"public/audio/last-apple.wav": "4cb2a8579fa3a7b91bb36363826ce8ca0d6d86e96e16a479e226a2802edd82f7",
"public/audio/last-furniture.wav": "5ad4f776e35439d408abed0e66567d6b5cdc80fc54d579165472e474f1238776",
"public/audio/last-hat.wav": "bdaf8fbc54df8061e9e58aa8c14b3044a6e863dc54973ee3ee6ae2c5ae1a28f1",
"public/audio/last-market.wav": "7857e87e9dbfe8fe849cc0b18c1d45b60916cb337328099c7a87a42c82e2821e",
"public/audio/last-meat.wav": "10f8ad4259ed8945c9da831e80b3902303c09caef96d400298599168fb1efed4",
"public/audio/last-oil.wav": "b5ce34950b8b31b1baf6ce55410797f0d8aa5478a670d6eace87cf76d134d6d3",
"public/audio/last-sea.wav": "f755452e1da44674aa1df7d12edffa988091b89a394e7eb6d4a00eb721f07cbf",
"public/audio/last-sound.wav": "ec9c49802aebeb6a8b898a1c0d8ad1daa127d2d64c905c197ed49a8e0c4eb64a",
"public/audio/last-tree.wav": "589e56d940a3c9e80ec02ae0b2dd93463fdc85ef019a753fcd0fded0752055f9",
"public/audio/last-umbrella.wav": "c801293a34013a8d93d3289a2cc87cd3eed83f97ba4647f5060efa00b117a9ad",
"public/audio/luck-apple.wav": "7c8f413f4b7e164f090e508ba090448f1376c6012649bbb6a917d45851313883",
"public/audio/luck-furniture.wav": "52cb92cdb8ee92b6f581c9d68dbc346f180c470564809ba57185429c9eb84127",
"public/audio/luck-hat.wav": "4ff43dd042f4b5451e9fdeb3edd59f1e389a7d1dd488094587a3a9fc7dfffa44",
"public/audio/luck-market.wav": "356af25332bf2000ed349671f3ff39767929e1f4599af622c021f907d11fb7bf",
"public/audio/luck-meat.wav": "d36dfc395a5c53fbfa4abe9980db7bb59adfdac59e40318c4aca365365e3f2ab",
"public/audio/luck-oil.wav": "3fa1e662a3af8f2726b17b2baa5bec2934406e6595ebc243c8380dd16e190977",
"public/audio/luck-sea.wav": "47aa31d757c9fb49c9b53a1c052d90a5ced4be57549d649850d9b48f8864045b",
"public/audio/luck-sound.wav": "34e4d9758d2ed448646fda364610e34779c84794403d9051ab3d8c1d33e2c80c",
"public/audio/luck-tree.wav": "122f496834fb16d6da47f801e50e46e272e4e934af959467d1db4e490f79be7a",
"public/audio/luck-umbrella.wav": "8d3e8e8bc97e5fe3f3362184c4abb12f01a882a1f1174d2644f0f70aac677c0a",
"public/audio/manifest.json": "ec4c6f3c86ba5083989a2da51150476a37b0a2d3152f202d1c82ed10a7aaa34b",
"public/audio/message-apple.wav": "d85e6f47d871369f00de2274139e5ad6b4b5686b5e20e248df0ed6b9a320d942",
"public/audio/message-furniture.wav": "26c331b7e12311236f4bb48f88918dfbf53cccd2f50b55741ea6ff4473e71dd8",
"public/audio/message-hat.wav": "5a713a8522b231bb8276805c014b385b9150b79f58ff2618446607e2b442495e",
"public/audio/message-market.wav": "9242d4cd6e0030e6b073e4d2360f84aa8a454d1749711cdb2d64c14f28a7ea20",
"public/audio/message-meat.wav": "ce19735df079b54c171e775b6b365385a80160b9033442abab95b2b9c8505e1a",
"public/audio/message-oil.wav": "a2a71a7e5e07c81871a25c6cb7540c39aa0b32fc44f78cda66b5f34ace98d805",
"public/audio/message-sea.wav": "28a461fbe03bffe2560030dea8b60715f7c0fe262dcf85b5b7f7daf483836382",
"public/audio/message-sound.wav": "1e682147dae8026ba78dc8f256c7f24acb3a6743bfd88a0fcc86096930eef078",
"public/audio/message-tree.wav": "5d684aa710a63d36ed8dcc2a8bfbdd5c71b0b1c63dad2a324adecb76591e85b8",
"public/audio/message-umbrella.wav": "41d5866dae66600df4694a8312b531571d44cece6dba0e423e7c43d09d184819",
"public/audio/middle-apple.wav": "8832f1b793ab3eedbe663875ea8dbeabb122c329bd5879437c71230b0418c3c8",
"public/audio/middle-furniture.wav": "b45b1afc8d9b534ff3e0a2a2ecb99efc1f4e40d41f89f55c4ed8ba94ad6d76d4",
"public/audio/middle-hat.wav": "b01ef9762ac84e3eb757243bc9286c62f7d45444a821ae35ac36a8b095e1598a",
"public/audio/middle-market.wav": "c855b449e0d4ace74681bfe68e5e7f0b063568827ae872017234dbe8ae119e4c",
"public/audio/middle-meat.wav": "d416107cc05e7c5b92ca27100a10a8a9689de913346179945d5542de4a6bac0c",
"public/audio/middle-oil.wav": "7a6b122b11c07da86c95fb78e2db2a70681b5219c63d6441fe56da1979ac1dc3",
"public/audio/middle-sea.wav": "b6dbe0af143ea775f05bd59a3d6af348bcc770ab378ac91ea75a56e06c326edf",
"public/audio/middle-sound.wav": "4d00aa6114327f450a00dacbc7e7b572ebf1de4ce9dc2fe4b5505766cca71ce9",
"public/audio/middle-tree.wav": "341888c75275c13eb31058f53a1d4276be0daa0a1b5a3a45522036928b83b0c1",
"public/audio/middle-umbrella.wav": "399ea2f681f755918f1117c8baba42739ceca64b307b999342f457a9235050b6",
"public/audio/mission-apple.wav": "3ef42e276ff3500c3e197d149f29f79d6a0c1d5516ed1d5a2c57210333fded9c",
"public/audio/mission-furniture.wav": "af82e03b686635c3356e706fe5b05c1231aeaaeab33f275aa5b8714988c65d43",
"public/audio/mission-hat.wav": "308278ec2bd27d4224976a55632d1f7fa1edabb0792126d9d858a699c287aee4",
"public/audio/mission-market.wav": "cefa0e95649ea6bd1df4c8dfccd2b74b4f4c028714420ce1087b61db2f2a8d47",
"public/audio/mission-meat.wav": "94f8a4f9e116a787e5ed052661d6de9ecf3ad8629db476661dd59ad03014b0c9",
"public/audio/mission-oil.wav": "5fb63e04520c312aa6b7b48b70c2f7c140b5ab480e5c6992edbc2ba85b9a06e7",
"public/audio/mission-sea.wav": "8838d6a1ee8a790427dc5aa761e70b3d8872af62086efeed743297ff7f8b8a06",
"public/audio/mission-sound.wav": "659eb0e2b06e6b165b46744769743e032e2282519f8486c57bc45e0f7d07a069",
"public/audio/mission-tree.wav": "00d8e77ec0371971d632724d91f8cf8d947bfb83c582a513b6421be4c457a1da",
"public/audio/mission-umbrella.wav": "4b4c858a25659540f9dbc524664496fc6de61ab8c1627f3cfee8c9c744e11d5b",
"public/audio/password-apple.wav": "b6f5de3fe571fe3a7fdb722fe49250bcfeedef49475271e0ec76a7630907edd5",
"public/audio/password-furniture.wav": "fb2b631dd4e12120d08a84cce6450f9cd9cd68105d13d7001d808e7deaa1df4a",
"public/audio/password-hat.wav": "e91bfc97df90a1675b6cd856880ac15c54de32cfc3b23603bdd1c2c5ac3ce6b8",
"public/audio/password-market.wav": "02e325fb753ef7a3ee585a03d2ca2aa3f1fbc58523b062222ae1136eeed7a95c",
"public/audio/password-meat.wav": "b009caadd56350d6a641ff17f0973e2b2724c183e1f45ae0bf3c483e237fa99e",
"public/audio/password-oil.wav": "b472957b27ff98ea7b8894fa1ff12653f7e9f66f77870faa9e52a1c1bf116c41",
"public/audio/password-sea.wav": "03f45b8cb5b3dc72faf5c6e3d0e2a10cea6b60301ea400d0a4453596d2f0b337",
"public/audio/password-sound.wav": "044aafff08a19e39f21e58b963644715a987cd155896998769ef8e9ce6449628",
"public/audio/password-tree.wav": "67da8147296e35134ec254bc82b58317630061b2c64d2d63c4be197ce8692d50",
"public/audio/password-umbrella.wav": "ab3ca6398c879971dc793eb25b472fcc0db72d76e386f11ef4d32c639f37c69d",
"public/audio/remember-apple.wav": "1bf2aef9a9f030af1a8fd7dee8f44aa420a397b3ba99b575feeb3dc7a63ec191",
"public/audio/remember-furniture.wav": "442bdcb956f120c270e1f321feae0415c897de0183e468980fcc119b898b2a67",
"public/audio/remember-hat.wav": "31a6a4270bf368cda419094d87a303ac3cd5c22539786cb165f8044b0b8e9d6e",
"public/audio/remember-market.wav": "d89792da51c83ac49d27e55aa6d822a338899a5ee487b34b552748201e1522f6",
"public/audio/remember-meat.wav": "9183ef90b64f5ceaf3bb0178c689231ff3e9981d6ce889124a15f2a6e2b7a344",
"public/audio/remember-oil.wav": "3ca98682ff06d1d6b8af02c0fd5b2124f42266ac989884223eff4a9bbde1287a",
"public/audio/remember-sea.wav": "5c91a36496e274d2be9c6fa8d9b506cd04f2a1b7ceb05ed1b7bb03fe7fca99d9",
"public/audio/remember-sound.wav": "98387ccc7aab566f6487d4c250b2128082cc527e013a6f7b7bc4d0266ac295df",
"public/audio/remember-tree.wav": "bc8e54f5407e8866bf1ca1ddfd4f6c63d85fee29bd9e430c7dd33e87974fc5b8",
"public/audio/remember-umbrella.wav": "c8988e604ba05d52597e561389541e8f9cda86e052279f1862bbf8399ead314e",
"public/audio/repeat-apple.wav": "cb7da4e9a1288cac64d168b241f27d7d2bc2dfecace58744f9bbf2792dfad04e",
"public/audio/repeat-furniture.wav": "bf84dc6cff1f227924a3a62158d2fc18769fb0ca40b91418fa19e534dbf92f00",
"public/audio/repeat-hat.wav": "6e089a42fd7e65e82eec7186d369c926fb7fdac794365b2bd7658822fd92437c",
"public/audio/repeat-market.wav": "68a5b899115a66ab225d610ec47b4de56cc8793657362bc38f533c06f741e4cc",
"public/audio/repeat-meat.wav": "6599d2fac73ea616a793151b4ce6f51af673988d630bac6219a77e78ae6cb34e",
"public/audio/repeat-oil.wav": "55b2c7d6aa8bbce04edf8661882c9781da81c57f56217f99b80457a3bb895da0",
"public/audio/repeat-sea.wav": "db2f235bee26ac804b5362e8e013b8f40c8da24fd3a34e0fb3b43c6d264feb36",
"public/audio/repeat-sound.wav": "e9d636ff7f4777f38b1ff15bebdcec6fbde95b4b4b05625a7415b4cfa0025b59",
"public/audio/repeat-tree.wav": "8735c3d9672561ca237fa87317beec2878492eb9063d6048d5b214423561acc1",
"public/audio/repeat-umbrella.wav": "5e59ef39113c3d5e106862356d715f4cef2862ef8ee02654a97e532675c1ac6d",
".agent/RESULT.md": "eef6d73a67a8a7e90cd7b4747debc5976cc51571bc268328634413f698d0e311",
"package.json": "41ba1d6c1e9f6350cf3bbc627b921839d67f7f9a20809d082f0c112ce7dbf631",
"package-lock.json": "9c64fc6a305196b84e39ac52405210b926c1431055724d82b41eafd21d542e5c"
}
}
@@ -0,0 +1,235 @@
UTC: 2026-10-14T07:20:59.789143+00:00
COMMAND: npm test -- tests/audio.test.ts tests/game.test.ts tests/audio-requests.test.ts
> find-word@0.1.1 test
> vitest run tests/audio.test.ts tests/game.test.ts tests/audio-requests.test.ts
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.1.1
❯ tests/audio-requests.test.ts (1 test | 1 failed) 28ms
× WAV 요청 판정은 query의 버전·순서와 무관하게 pathname을 사용한다 26ms
❯ tests/game.test.ts (8 tests | 1 failed) 92ms
❯ 출제와 정답 판정 (5)
× 목표 WAV 100개 모두 같은 명시적 cache-busting 버전과 정답 mapping을 유지한다 50ms
❯ tests/audio.test.ts (8 tests | 3 failed) 357ms
❯ 오디오 재생 수명과 믹서 (8)
× intro와 목표 실제 fetch URL에 같은 명시적 cache-busting 버전을 붙인다 101ms
× intro 404 후 intro·목표를 동일한 versioned URL로 다시 요청한다 47ms
× target 404 후 intro·목표를 동일한 versioned URL로 다시 요청한다 47ms
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 5 ⎯⎯⎯⎯⎯⎯⎯
FAIL tests/audio-requests.test.ts > WAV 요청 판정은 query의 버전·순서와 무관하게 pathname을 사용한다
AssertionError: /audio/intro.wav?v=0.1.1: expected false to be true // Object.is equality
- Expected
+ Received
- true
+ false
❯ tests/audio-requests.test.ts:12:74
10| "/audio/luck-apple.wav",
11| ]) {
12| expect.soft(isAudioRequest(new URL(path, "http://localhost")), pat…
| ^
13| }
14| for (const path of [
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/11]⎯
FAIL tests/audio-requests.test.ts > WAV 요청 판정은 query의 버전·순서와 무관하게 pathname을 사용한다
AssertionError: /audio/luck-apple.wav?v=0.1.1: expected false to be true // Object.is equality
- Expected
+ Received
- true
+ false
❯ tests/audio-requests.test.ts:12:74
10| "/audio/luck-apple.wav",
11| ]) {
12| expect.soft(isAudioRequest(new URL(path, "http://localhost")), pat…
| ^
13| }
14| for (const path of [
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/11]⎯
FAIL tests/audio-requests.test.ts > WAV 요청 판정은 query의 버전·순서와 무관하게 pathname을 사용한다
AssertionError: /audio/luck-apple.wav?retry=1&v=0.1.1: expected false to be true // Object.is equality
- Expected
+ Received
- true
+ false
❯ tests/audio-requests.test.ts:12:74
10| "/audio/luck-apple.wav",
11| ]) {
12| expect.soft(isAudioRequest(new URL(path, "http://localhost")), pat…
| ^
13| }
14| for (const path of [
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/11]⎯
FAIL tests/audio-requests.test.ts > WAV 요청 판정은 query의 버전·순서와 무관하게 pathname을 사용한다
AssertionError: /audio/luck-apple.wav?v=0.1.1&retry=1: expected false to be true // Object.is equality
- Expected
+ Received
- true
+ false
❯ tests/audio-requests.test.ts:12:74
10| "/audio/luck-apple.wav",
11| ]) {
12| expect.soft(isAudioRequest(new URL(path, "http://localhost")), pat…
| ^
13| }
14| for (const path of [
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/11]⎯
FAIL tests/audio-requests.test.ts > WAV 요청 판정은 query의 버전·순서와 무관하게 pathname을 사용한다
AssertionError: /audio/manifest.json?file=intro.wav: expected true to be false // Object.is equality
- Expected
+ Received
- false
+ true
❯ tests/audio-requests.test.ts:20:74
18| "/audio/intro.wav.txt?v=0.1.1",
19| ]) {
20| expect.soft(isAudioRequest(new URL(path, "http://localhost")), pat…
| ^
21| }
22| });
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/11]⎯
FAIL tests/audio-requests.test.ts > WAV 요청 판정은 query의 버전·순서와 무관하게 pathname을 사용한다
AssertionError: /other/intro.wav: expected true to be false // Object.is equality
- Expected
+ Received
- false
+ true
❯ tests/audio-requests.test.ts:20:74
18| "/audio/intro.wav.txt?v=0.1.1",
19| ]) {
20| expect.soft(isAudioRequest(new URL(path, "http://localhost")), pat…
| ^
21| }
22| });
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/11]⎯
FAIL tests/audio-requests.test.ts > WAV 요청 판정은 query의 버전·순서와 무관하게 pathname을 사용한다
AssertionError: /audio-backup/intro.wav: expected true to be false // Object.is equality
- Expected
+ Received
- false
+ true
❯ tests/audio-requests.test.ts:20:74
18| "/audio/intro.wav.txt?v=0.1.1",
19| ]) {
20| expect.soft(isAudioRequest(new URL(path, "http://localhost")), pat…
| ^
21| }
22| });
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/11]⎯
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > intro와 목표 실제 fetch URL에 같은 명시적 cache-busting 버전을 붙인다
AssertionError: expected [ '/audio/intro.wav', …(1) ] to deeply equal [ '/audio/intro.wav?v=0.1.1', …(1) ]
- Expected
+ Received
[
- "/audio/intro.wav?v=0.1.1",
- "/audio/correction-market.wav?v=0.1.1",
+ "/audio/intro.wav",
+ "/audio/correction-market.wav",
]
❯ tests/audio.test.ts:97:54
95| f.sources.at(-1)!.onended?.();
96| await done;
97| expect(f.fetcher.mock.calls.map(([url]) => url)).toEqual([
| ^
98| "/audio/intro.wav?v=0.1.1",
99| `/audio/${question.id}.wav?v=0.1.1`,
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/11]⎯
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > intro 404 후 intro·목표를 동일한 versioned URL로 다시 요청한다
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > target 404 후 intro·목표를 동일한 versioned URL로 다시 요청한다
AssertionError: expected [ '/audio/intro.wav', …(3) ] to deeply equal [ '/audio/intro.wav?v=0.1.1', …(3) ]
- Expected
+ Received
[
- "/audio/intro.wav?v=0.1.1",
- "/audio/correction-market.wav?v=0.1.1",
- "/audio/intro.wav?v=0.1.1",
- "/audio/correction-market.wav?v=0.1.1",
+ "/audio/intro.wav",
+ "/audio/correction-market.wav",
+ "/audio/intro.wav",
+ "/audio/correction-market.wav",
]
❯ tests/audio.test.ts:119:54
117| f.sources.at(-1)!.onended?.();
118| await done;
119| expect(f.fetcher.mock.calls.map(([url]) => url)).toEqual([
| ^
120| "/audio/intro.wav?v=0.1.1",
121| `/audio/${question.id}.wav?v=0.1.1`,
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/11]⎯
FAIL tests/game.test.ts > 출제와 정답 판정 > 목표 WAV 100개 모두 같은 명시적 cache-busting 버전과 정답 mapping을 유지한다
AssertionError: expected Set{ null } to deeply equal Set{ '0.1.1' }
- Expected
+ Received
Set {
- "0.1.1",
+ null,
}
❯ tests/game.test.ts:30:22
28| versions.add(url.searchParams.get("v"));
29| }
30| expect(versions).toEqual(new Set(["0.1.1"]));
| ^
31| });
32| it("실제 보기에 있는 경쟁 단어를 문장에 넣고 청취 연산별 순서를 유지한다", () => {
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/11]⎯
Test Files 3 failed (3)
Tests 5 failed | 12 passed (17)
Start at 07:21:00
Duration 1.91s (environment 66%, setup 13%, tests 11%, transform 6%, worker 2%, import 2%)
EXIT_CODE: 1
@@ -0,0 +1,19 @@
UTC: 2026-10-14T07:21:00.984991+00:00
COMMAND: npm run build
> find-word@0.1.1 build
> tsc --noEmit && vite build && node scripts/check-build.mjs
vite v8.3.4 building client environment for production...
transforming...
✓ 20 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 0.89 kB │ gzip: 0.63 kB
dist/assets/index-KT6VDfPn.css 15.25 kB │ gzip: 4.39 kB
dist/assets/index-CorsjeLi.js 245.34 kB │ gzip: 77.26 kB
✓ built in 177ms
빌드 음성 자산 101개 및 런타임 notice 전문 확인
EXIT_CODE: 0
@@ -0,0 +1,148 @@
UTC: 2026-10-14T07:21:27.811844+00:00
COMMAND: env -u PLAYWRIGHT_NO_SANDBOX CHROME_PATH=/usr/bin/google-chrome npm run test:browser -- tests/browser/game.spec.ts tests/browser/audio.spec.ts --project=desktop
> find-word@0.1.1 test:browser
> playwright test tests/browser/game.spec.ts tests/browser/audio.spec.ts --project=desktop
[WebServer] (node:796454) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
Running 4 tests using 2 workers
(node:796474) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:796475) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
✘ 1 [desktop] › tests/browser/audio.spec.ts:7:1 › intro·목표 101개 versioned WAV를 실제 Chrome에서 해시·디코드 검증한다 (1.8s)
(node:796732) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
✘ 2 [desktop] › tests/browser/game.spec.ts:8:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 (3.0s)
✘ 3 [desktop] › tests/browser/game.spec.ts:124:3 › intro WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (805ms)
(node:796861) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
✘ 4 [desktop] › tests/browser/game.spec.ts:124:3 › target WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (666ms)
1) [desktop] › tests/browser/audio.spec.ts:7:1 › intro·목표 101개 versioned WAV를 실제 Chrome에서 해시·디코드 검증한다
Error: expect(received).toEqual(expected) // deep equality
- Expected - 1
+ Received + 1
Set {
- "0.1.1",
+ null,
}
30 | expect(targetUrls).toHaveLength(100);
31 | const urls = [introUrl, ...targetUrls.map((url) => new URL(url, page.url()).href)];
> 32 | expect(new Set(urls.map((url) => new URL(url).searchParams.get("v")))).toEqual(new Set(["0.1.1"]));
| ^
33 | expect(urls.every((url) => new URL(url).origin === new URL(page.url()).origin)).toBe(true);
34 | const manifest = JSON.parse(readFileSync("public/audio/manifest.json", "utf8")) as {
35 | version: string;
at /home/hermes/worktrees/find-word-v0.1.1/tests/browser/audio.spec.ts:32:74
Error Context: test-results/audio-intro·목표-101개-versioned-WAV를-실제-Chrome에서-해시·디코드-검증한다-desktop/error-context.md
attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/audio-intro·목표-101개-versioned-WAV를-실제-Chrome에서-해시·디코드-검증한다-desktop/trace.zip
Usage:
npx playwright show-trace test-results/audio-intro·목표-101개-versioned-WAV를-실제-Chrome에서-해시·디코드-검증한다-desktop/trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
2) [desktop] › tests/browser/game.spec.ts:8:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 ───────────────
Error: expect(received).toEqual(expected) // deep equality
- Expected - 2
+ Received + 2
Array [
- "0.1.1",
- "0.1.1",
+ null,
+ null,
]
42 | await page.getByRole("button", { name: "게임 시작 · 소리 듣기" }).click();
43 | await expect.poll(() => audioUrls.length).toBe(2);
> 44 | expect(audioUrls.map((url) => url.searchParams.get("v"))).toEqual(["0.1.1", "0.1.1"]);
| ^
45 | await expect(page.getByRole("button", { name: /듣는 중/ })).toBeDisabled();
46 | await expect(page.locator(".sound-wave.active i").first()).toHaveCSS(
47 | "animation-name",
at /home/hermes/worktrees/find-word-v0.1.1/tests/browser/game.spec.ts:44:61
Error Context: test-results/game-실제-오디오로-혼합-모드-완주·레이아웃·접근성·외부-요청-없음-desktop/error-context.md
attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/game-실제-오디오로-혼합-모드-완주·레이아웃·접근성·외부-요청-없음-desktop/trace.zip
Usage:
npx playwright show-trace test-results/game-실제-오디오로-혼합-모드-완주·레이아웃·접근성·외부-요청-없음-desktop/trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
3) [desktop] › tests/browser/game.spec.ts:124:3 › intro WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다
Error: expect(received).toBe(expected) // Object.is equality
Expected: "0.1.1"
Received: null
138 | await expect(page.getByRole("alert")).toContainText("소리를 재생하지 못했어요");
139 | expect(missing).toHaveLength(1);
> 140 | expect(new URL(missing[0]!).searchParams.get("v")).toBe("0.1.1");
| ^
141 | expect(audioUrls).toHaveLength(2);
142 | await page.unroute(matchesFailure);
143 | await page.getByRole("button", { name: "다시 시도" }).click();
at /home/hermes/worktrees/find-word-v0.1.1/tests/browser/game.spec.ts:140:56
Error Context: test-results/game-intro-WAV-query-URL의-404를-표시하고-같은-URL로-재시도·정답-mapping한다-desktop/error-context.md
attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/game-intro-WAV-query-URL의-404를-표시하고-같은-URL로-재시도·정답-mapping한다-desktop/trace.zip
Usage:
npx playwright show-trace test-results/game-intro-WAV-query-URL의-404를-표시하고-같은-URL로-재시도·정답-mapping한다-desktop/trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
4) [desktop] › tests/browser/game.spec.ts:124:3 › target WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다
Error: expect(received).toBe(expected) // Object.is equality
Expected: "0.1.1"
Received: null
138 | await expect(page.getByRole("alert")).toContainText("소리를 재생하지 못했어요");
139 | expect(missing).toHaveLength(1);
> 140 | expect(new URL(missing[0]!).searchParams.get("v")).toBe("0.1.1");
| ^
141 | expect(audioUrls).toHaveLength(2);
142 | await page.unroute(matchesFailure);
143 | await page.getByRole("button", { name: "다시 시도" }).click();
at /home/hermes/worktrees/find-word-v0.1.1/tests/browser/game.spec.ts:140:56
Error Context: test-results/game-target-WAV-query-URL의-8e3ab-하고-같은-URL로-재시도·정답-mapping한다-desktop/error-context.md
attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
test-results/game-target-WAV-query-URL의-8e3ab-하고-같은-URL로-재시도·정답-mapping한다-desktop/trace.zip
Usage:
npx playwright show-trace test-results/game-target-WAV-query-URL의-8e3ab-하고-같은-URL로-재시도·정답-mapping한다-desktop/trace.zip
────────────────────────────────────────────────────────────────────────────────────────────────
4 failed
[desktop] › tests/browser/audio.spec.ts:7:1 › intro·목표 101개 versioned WAV를 실제 Chrome에서 해시·디코드 검증한다
[desktop] › tests/browser/game.spec.ts:8:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 ────────────────
[desktop] › tests/browser/game.spec.ts:124:3 › intro WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다
[desktop] › tests/browser/game.spec.ts:124:3 › target WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다
EXIT_CODE: 1
@@ -0,0 +1,22 @@
{
"utc": "2026-10-14T07:22:25.563434+00:00",
"productionSourceDiff": "",
"unitRed": {
"failed": 5,
"passed": 12,
"exitCode": 1
},
"browserRed": {
"failed": 4,
"exitCode": 1
},
"sources": {
"src/App.tsx": "1ebde5bd2aa8038e5e003e4b9c84071bd9571dc2deff334b848720761d43df19",
"src/audio/dsp.ts": "e51176acc381b7e9d1fc19d7f3fdeb87f6b653dad13a332470104e957e973ecc",
"src/audio/engine.ts": "2d2272c8690d1b791fb51e111e1408e1a9688f8b6abb49f7ccf7bef5e8091543",
"src/content.ts": "f7363aaa6dd99f56e733843c569e96018a9c570708bea25857af59548f45e2c5",
"src/game.ts": "7aac9bccb6c322288d22966ee672da17d6745205260c8e87e009a3704ea8bd89",
"src/main.tsx": "eeab7184c76db4d03f45af69697f19affaaf318de056e36c8782000807d5e88e",
"src/styles.css": "09a32cc57163e1f517075525d98ffcf783b18e872135163f7572ac60ace25b9f"
}
}
@@ -0,0 +1,17 @@
UTC: 2026-10-14T07:22:34.296917+00:00
COMMAND: npm test -- tests/audio.test.ts tests/game.test.ts tests/audio-requests.test.ts
> find-word@0.1.1 test
> vitest run tests/audio.test.ts tests/game.test.ts tests/audio-requests.test.ts
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.1.1
Test Files 3 passed (3)
Tests 17 passed (17)
Start at 07:22:34
Duration 1.57s (environment 72%, setup 13%, tests 7%, transform 6%, worker 1%, import 1%)
EXIT_CODE: 0
@@ -0,0 +1,8 @@
UTC: 2026-10-14T07:23:10.118081+00:00
COMMAND: npm run lint
> find-word@0.1.1 lint
> eslint . && tsc --noEmit
EXIT_CODE: 0
@@ -0,0 +1,20 @@
UTC: 2026-10-14T07:23:10.132588+00:00
COMMAND: npm test
> find-word@0.1.1 test
> vitest run
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.1.1
Test Files 12 passed (12)
Tests 65 passed (65)
Start at 07:23:10
Duration 14.73s (tests 71%, environment 20%, setup 7%, import 1%)
Isolate 12 workers spawned · ~883ms startup each (spawn + environment, per file)
at least ~2.65s faster with isolate: false — reuses workers across files instead of one per file
EXIT_CODE: 0
@@ -0,0 +1,19 @@
UTC: 2026-10-14T07:23:10.144409+00:00
COMMAND: npm run build
> find-word@0.1.1 build
> tsc --noEmit && vite build && node scripts/check-build.mjs
vite v8.3.4 building client environment for production...
transforming...
✓ 21 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 0.89 kB │ gzip: 0.63 kB
dist/assets/index-KT6VDfPn.css 15.25 kB │ gzip: 4.39 kB
dist/assets/index-CNSv_hb8.js 245.39 kB │ gzip: 77.28 kB
✓ built in 654ms
빌드 음성 자산 101개 및 런타임 notice 전문 확인
EXIT_CODE: 0
@@ -0,0 +1,84 @@
UTC: 2026-10-14T07:23:35.351749+00:00
COMMAND: env -u PLAYWRIGHT_NO_SANDBOX CHROME_PATH=/usr/bin/google-chrome DEBUG=pw:browser npm run test:browser
> find-word@0.1.1 test:browser
> playwright test
[WebServer] (node:797635) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
Running 16 tests using 2 workers
(node:797656) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
(node:797657) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-VLndm1 --remote-debugging-pipe --no-startup-window +0ms
pw:browser <launched> pid=797676 +6ms
pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-E3SrLp --remote-debugging-pipe --no-startup-window +0ms
pw:browser <launched> pid=797720 +11ms
pw:browser [pid=797676][err] [797729:797729:1014/072337.395281:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +151ms
pw:browser [pid=797720][err] [797806:797806:1014/072337.559739:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +228ms
pw:browser [pid=797676][err] [797822:7:1014/072337.636786:ERROR:gpu/ipc/client/command_buffer_proxy_impl.cc:287] ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer. +236ms
pw:browser [pid=797676][err] [797884:797884:1014/072338.237452:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +600ms
pw:browser [pid=797720][err] [797908:797908:1014/072339.957896:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +2s
✓ 1 [desktop] › tests/browser/audio.spec.ts:7:1 › intro·목표 101개 versioned WAV를 실제 Chrome에서 해시·디코드 검증한다 (3.5s)
pw:browser [pid=797720][err] [797720:797786:1014/072343.442681:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: QUOTA_EXCEEDED +3s
pw:browser [pid=797676][err] [797676:797709:1014/072344.514117:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +6s
✓ 3 [desktop] › tests/browser/game.spec.ts:130:3 › intro WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (15.7s)
✓ 4 [desktop] › tests/browser/game.spec.ts:130:3 › target WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (13.7s)
✓ 5 [desktop] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (312ms)
✓ 6 [desktop] › tests/browser/ui.spec.ts:4:1 › 전체 음량은 설정 흐름 안에 들어가며 키보드로 조절된다 (1.2s)
✓ 7 [desktop] › tests/browser/ui.spec.ts:52:1 › 난이도 설명은 모바일에서도 보인다 (852ms)
pw:browser [pid=797676][err] [797676:797709:1014/072414.236741:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +30s
✓ 8 [desktop] › tests/browser/ui.spec.ts:68:1 › 한국어 제목은 단어 중간에서 줄바꿈하지 않는다 (16.7s)
pw:browser [pid=797676] <gracefully close start> +15s
pw:browser [pid=797676] <process did exit: exitCode=0, signal=null> +63ms
pw:browser [pid=797676] starting temporary directories cleanup +1ms
pw:browser [pid=797676] finished temporary directories cleanup +8ms
pw:browser [pid=797676] <gracefully close end> +0ms
(node:798432) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-98ggzR --remote-debugging-pipe --no-startup-window +0ms
pw:browser <launched> pid=798444 +6ms
pw:browser [pid=798444][err] [798487:798487:1014/072430.332265:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +129ms
pw:browser [pid=798444][err] [798525:7:1014/072430.474467:ERROR:gpu/ipc/client/command_buffer_proxy_impl.cc:287] ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer. +141ms
pw:browser [pid=798444][err] [798546:798546:1014/072430.822117:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +347ms
✓ 9 [mobile] › tests/browser/audio.spec.ts:7:1 › intro·목표 101개 versioned WAV를 실제 Chrome에서 해시·디코드 검증한다 (2.6s)
pw:browser [pid=798444][err] [798444:798472:1014/072437.625010:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: QUOTA_EXCEEDED +7s
✓ 2 [desktop] › tests/browser/game.spec.ts:8:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 (1.7m)
pw:browser [pid=797720] <gracefully close start> +2m
pw:browser [pid=797720] <process did exit: exitCode=0, signal=null> +58ms
pw:browser [pid=797720] starting temporary directories cleanup +0ms
pw:browser [pid=797720] finished temporary directories cleanup +9ms
pw:browser [pid=797720] <gracefully close end> +0ms
(node:798715) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
pw:browser <launching> /usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-n2iw8E --remote-debugging-pipe --no-startup-window +0ms
pw:browser <launched> pid=798727 +6ms
pw:browser [pid=798727][err] [798770:798770:1014/072519.143522:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +114ms
pw:browser [pid=798727][err] [798809:7:1014/072519.291872:ERROR:gpu/ipc/client/command_buffer_proxy_impl.cc:287] ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer. +146ms
pw:browser [pid=798727][err] [798831:798831:1014/072519.654215:ERROR:base/memory/shared_memory_switch.cc:289] Failed global descriptor lookup: 7 +362ms
pw:browser [pid=798727][err] [798727:798755:1014/072523.099951:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +3s
✓ 11 [mobile] › tests/browser/game.spec.ts:130:3 › intro WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (17.1s)
pw:browser [pid=798727][err] [798727:798755:1014/072550.990604:ERROR:google_apis/gcm/engine/registration_request.cc:291] Registration response error message: DEPRECATED_ENDPOINT +28s
✓ 12 [mobile] › tests/browser/game.spec.ts:130:3 › target WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (15.9s)
✓ 13 [mobile] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (308ms)
✓ 14 [mobile] › tests/browser/ui.spec.ts:4:1 › 전체 음량은 설정 흐름 안에 들어가며 키보드로 조절된다 (976ms)
✓ 15 [mobile] › tests/browser/ui.spec.ts:52:1 › 난이도 설명은 모바일에서도 보인다 (772ms)
✓ 16 [mobile] › tests/browser/ui.spec.ts:68:1 › 한국어 제목은 단어 중간에서 줄바꿈하지 않는다 (16.8s)
pw:browser [pid=798727] <gracefully close start> +20s
pw:browser [pid=798727] <process did exit: exitCode=0, signal=null> +45ms
pw:browser [pid=798727] starting temporary directories cleanup +0ms
pw:browser [pid=798727] finished temporary directories cleanup +8ms
pw:browser [pid=798727] <gracefully close end> +0ms
✓ 10 [mobile] › tests/browser/game.spec.ts:8:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 (1.7m)
pw:browser [pid=798444] <gracefully close start> +2m
pw:browser [pid=798444] <process did exit: exitCode=0, signal=null> +57ms
pw:browser [pid=798444] starting temporary directories cleanup +0ms
pw:browser [pid=798444] finished temporary directories cleanup +10ms
pw:browser [pid=798444] <gracefully close end> +0ms
16 passed (2.6m)
EXIT_CODE: 0
@@ -0,0 +1,40 @@
UTC: 2026-10-14T07:23:54.730130+00:00
COMMAND: env -u PLAYWRIGHT_NO_SANDBOX node .cache/verify-cache-sandbox.mjs
node:internal/modules/run_main:107
triggerUncaughtException(
^
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /Namespace sandbox\s+Yes/. Input:
'Sandbox Status\n' +
'Layer 1 Sandbox\tNamespace\n' +
'PID namespaces\tYes\n' +
'Network namespaces\tYes\n' +
'Seccomp-BPF sandbox\tYes\n' +
'Seccomp-BPF sandbox supports TSYNC\tYes\n' +
'Ptrace Protection with Yama LSM (Broker)\tYes\n' +
'Ptrace Protection with Yama LSM (Non-broker)\tNo\n' +
'\n' +
'You are adequately sandboxed.'
at file:///home/hermes/worktrees/find-word-v0.1.1/.cache/verify-cache-sandbox.mjs:8:10 {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 'Sandbox Status\n' +
'Layer 1 Sandbox\tNamespace\n' +
'PID namespaces\tYes\n' +
'Network namespaces\tYes\n' +
'Seccomp-BPF sandbox\tYes\n' +
'Seccomp-BPF sandbox supports TSYNC\tYes\n' +
'Ptrace Protection with Yama LSM (Broker)\tYes\n' +
'Ptrace Protection with Yama LSM (Non-broker)\tNo\n' +
'\n' +
'You are adequately sandboxed.',
expected: /Namespace sandbox\s+Yes/,
operator: 'match',
diff: 'simple'
}
Node.js v26.7.0
EXIT_CODE: 1
@@ -0,0 +1,10 @@
UTC: 2026-10-14T07:24:19.461259+00:00
COMMAND: env -u PLAYWRIGHT_NO_SANDBOX node .cache/verify-cache-sandbox.mjs
{
"node": "v26.7.0",
"chrome": "146.0.7680.80",
"sandboxStatus": "Sandbox Status\nLayer 1 Sandbox\tNamespace\nPID namespaces\tYes\nNetwork namespaces\tYes\nSeccomp-BPF sandbox\tYes\nSeccomp-BPF sandbox supports TSYNC\tYes\nPtrace Protection with Yama LSM (Broker)\tYes\nPtrace Protection with Yama LSM (Non-broker)\tNo\n\nYou are adequately sandboxed.",
"commandLine": "/usr/bin/google-chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-edgeupdater --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints,NetworkTimeServiceQuerying,AimEnabled,msForceBrowserSignIn,msEdgeUpdateLaunchServicesPreferredVersion --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-updater-scheduler --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --headless --hide-scrollbars --mute-audio --blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 --user-data-dir=/tmp/playwright_chromiumdev_profile-1fbWzM --remote-debugging-pipe --no-startup-window --noerrdialogs --ozone-platform=headless --ozone-override-screen-size=800,600 --use-angle=swiftshader-webgl --flag-switches-begin --flag-switches-end --enable-unsafe-swiftshader"
}
EXIT_CODE: 0
@@ -0,0 +1,55 @@
2026-10-14 UTC — 배포 후 오디오 캐시 회귀 수정
발견 원인
- v0.1 → v0.1.1에서 intro 1개·목표 100개 WAV 내용이 바뀌었지만 파일명은 동일하다.
- src/game.ts와 src/audio/engine.ts가 버전 없는 /audio/*.wav URL을 요청했다.
- 사용자 보고에 따르면 배포 Nginx는 /audio를 7일 캐시한다. 기존 URL의 캐시가
유효한 사용자는 이전 음성을 계속 받는다. 이 작업은 원격 서버에 접속하지 않았다.
- 배포 문서는 expires -1을 가정했고, 브라우저 요청 관찰의 URL.endsWith('.wav')와
404 route의 **/audio/*.wav glob도 query string을 처리하지 못했다.
실제 RED → GREEN 순서
1. 앱 소스를 그대로 두고 unit/browser 계약 테스트를 먼저 작성했다.
기존 endsWith 판정을 공용 테스트 helper로 추출했으며 RED까지 동작은 그대로다.
2. 01-unit-red.log: 5 failed / 12 passed / exit 1.
목표 100개 버전, intro·target fetch, intro/target 각각 404 retry,
query 순서와 무관한 pathname 판정 및 가짜 .wav query 배제를 검출했다.
3. 02-build-before-fix.log: 수정 전 앱 production build 성공.
4. 03-browser-red.log: sandboxed Chrome desktop 4 failed / exit 1.
101개 URL, 실제 앱 요청/정답 mapping, intro/target 404 계약이 모두
v=null 대신 v=0.1.1을 기대하는 assertion에서 실패했다.
5. 04-red-state.json: 위 RED 완료 시점의 production source diff가 비어 있음을 기록.
6. 그 뒤 src/audio/assets.ts 한 곳에 AUDIO_ASSET_VERSION="0.1.1"과
audioAssetUrl을 정의하고 intro·target에 함께 적용했다.
테스트 요청 관찰·404 route·정답 mapping·101개 manifest 대응은 pathname 기준이다.
7. 05-unit-green.log: 같은 대상 17 passed / exit 0.
8. 09-browser-green.log: desktop/mobile 전체 16 passed (2.6m) / exit 0.
최종 검증
- npm run lint: PASS (06-lint.log, ESLint + TypeScript).
- npm test: PASS, 12 files / 65 tests, skip 0 (07-full-test.log).
Python 생성기 18개 계약도 기존 npm test runner를 통해 통과했다.
- npm run build: PASS, WAV 101개 hash 및 runtime notice 전문 (08-build.log).
- env -u PLAYWRIGHT_NO_SANDBOX CHROME_PATH=/usr/bin/google-chrome DEBUG=pw:browser
npm run test:browser: PASS, desktop/mobile 전체 16개, skip 0.
- 두 viewport 모두 실제 음성으로 10문제 완주·재청취·정답 mapping·intro/target
각각 404 복구·키보드·레이아웃·axe를 통과했다.
- 두 viewport 각각 101/101 query URL 요청·SHA-256·bytes·24kHz mono decode·
duration·RMS·peak 통과. 외부 페이지 요청 0, 페이지 JS 예외 0.
- Node 26.7.0 / npm 11.19.0 / system Chrome 146.0.7680.80.
- 11-sandbox-green.log: Layer 1 Namespace, PID/Network namespaces,
Seccomp-BPF/TSYNC 활성. 실제 실행 인자 --no-sandbox 없음.
10-sandbox.log는 보조 검사에서 Chrome 상태 라벨을 'Namespace sandbox Yes'로
잘못 가정한 실패 기록이다. 실제 표시 'Layer 1 Sandbox Namespace'와
PID/Network Yes를 검사하도록 보조 probe를 고친 뒤 11번에서 통과했다.
앱·Playwright sandbox 설정은 바꾸지 않았다.
기록 및 범위
- 제품 0.1.1 유지. WAV/manifest 재생성 및 package/lock 변경 없음.
- 런타임 버전 조회·외부 TTS/API 호출 없음. 저장 WAV의 상대 URL query만 추가했다.
- 스크린샷은 test-results/에 저장 후 이번 artifacts/로 복사했다.
과거 verify_browser.mjs, 로그, 스크린샷은 수정하거나 다시 실행해 덮어쓰지 않았다.
- 00-baseline.json의 기존 evidence 149개, 오디오 102개, 기존 RESULT.md,
package/lock 포함 총 254개 파일은 최종 13-final-integrity.json에서 해시 대조한다.
- .agent/RESULT-v0.1.1.md에는 이번 결과를 뒤에 추가한다.
- Git commit/push/tag/merge 및 서버 배포 실행 없음. 로컬 production preview만 사용했다.
@@ -0,0 +1,50 @@
{
"utc": "2026-10-14T07:27:57.445449+00:00",
"status": "PASS",
"productVersion": "0.1.1",
"preservedFiles": 254,
"preservedHistoricalEvidenceFiles": 149,
"preservedAudioFiles": 102,
"changedHistoricalFiles": [],
"headBefore": "a92b2ba1e973c65a57e6e34cc52568cd6b208c1e",
"headAfter": "a92b2ba1e973c65a57e6e34cc52568cd6b208c1e",
"previousResultContentPreservedAsPrefix": true,
"gitDiffCheck": "PASS",
"unit": {
"files": 12,
"tests": 65,
"skipped": 0
},
"browser": {
"tests": 16,
"skipped": 0,
"launchesWithoutNoSandbox": 4,
"projects": {
"desktop": {
"wavFiles": 101,
"cacheVersion": "0.1.1",
"externalRequests": 0,
"pageErrors": 0
},
"mobile": {
"wavFiles": 101,
"cacheVersion": "0.1.1",
"externalRequests": 0,
"pageErrors": 0
}
}
},
"sourceSha256": {
"src/audio/assets.ts": "beb8da92ab1ae6dae6bc3b4db37afefc72a07bbf089fe4ea5948043a9eead79a",
"src/audio/engine.ts": "971bbe451c984cb4209e9f0338c3b9b422035e9b1339484effb5d3c2a7e6352f",
"src/game.ts": "3d0fd88ebeebcd4f25696168dd07a669bf3161d620091a67bb81882aa87232aa",
"tests/audio.test.ts": "58ebce8a48b83dae6f45d92175b37ff1b5e654ea067d0b2658bc879162b0d488",
"tests/game.test.ts": "bcb03d0c2d84177664b5320d53fb5bf2b3865dbbdc3bb281caf47199a57620e1",
"tests/audio-requests.test.ts": "9496b5515982dfb2eb24d3e4bf99da11eac28812164eaa557443fdf716bd9dd3",
"tests/browser/audio-requests.ts": "3dff162cbc5a9b735fb8f911ed83ca04d646ba011511c4f922faf712f8094295",
"tests/browser/audio.spec.ts": "f26ea575d9e5471b5746471e6704a0694e1d0a4cde34f8c5faf66ff2d9df9d16",
"tests/browser/game.spec.ts": "64306590d39c90cc8fe208ff758b63ba889ca1581ee081c520dfd43e97d7df1e",
"tests/browser/ui.spec.ts": "a342a49f83a2ef7f1b78145be08a457463baf53a8fdfeac28649bcd7bc14bbbf"
},
"gitCommitPushTagMergeDeploymentPerformed": false
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

+161
View File
@@ -0,0 +1,161 @@
ADDED .agent/RESULT-v0.1.1.md
ADDED .agent/evidence-v0.1.1/00-audio-venv.log
ADDED .agent/evidence-v0.1.1/00-npm-ci.log
ADDED .agent/evidence-v0.1.1/01-version-docs-red.log
ADDED .agent/evidence-v0.1.1/02-assets-red.log
ADDED .agent/evidence-v0.1.1/03-generator-red.log
ADDED .agent/evidence-v0.1.1/04-generator-additional-red.log
ADDED .agent/evidence-v0.1.1/05-generator-green.log
ADDED .agent/evidence-v0.1.1/06-audio-generate.log
ADDED .agent/evidence-v0.1.1/07-format.log
ADDED .agent/evidence-v0.1.1/08-version-docs-green.log
ADDED .agent/evidence-v0.1.1/09-lint.log
ADDED .agent/evidence-v0.1.1/10-audit.log
ADDED .agent/evidence-v0.1.1/11-full-test.log
ADDED .agent/evidence-v0.1.1/12-independent-audio.log
ADDED .agent/evidence-v0.1.1/13-build.log
ADDED .agent/evidence-v0.1.1/14-browser.log
ADDED .agent/evidence-v0.1.1/15-browser-audio.log
ADDED .agent/evidence-v0.1.1/16-final-lint.log
ADDED .agent/evidence-v0.1.1/17-security-history.json
ADDED .agent/evidence-v0.1.1/18-environment.log
ADDED .agent/evidence-v0.1.1/19-final-integrity.json
ADDED .agent/evidence-v0.1.1/audio-integrity.json
ADDED .agent/evidence-v0.1.1/baseline.json
ADDED .agent/evidence-v0.1.1/browser-audio-integrity.json
ADDED .agent/evidence-v0.1.1/changed-files.txt
ADDED .agent/evidence-v0.1.1/desktop-game.png
ADDED .agent/evidence-v0.1.1/desktop-heading.png
ADDED .agent/evidence-v0.1.1/desktop-home.png
ADDED .agent/evidence-v0.1.1/desktop-results.png
ADDED .agent/evidence-v0.1.1/mobile-game.png
ADDED .agent/evidence-v0.1.1/mobile-heading.png
ADDED .agent/evidence-v0.1.1/mobile-home.png
ADDED .agent/evidence-v0.1.1/mobile-results.png
ADDED .agent/evidence-v0.1.1/verify_audio.py
ADDED .agent/evidence-v0.1.1/verify_browser.mjs
ADDED requirements-audio.txt
ADDED scripts/neural_audio.py
ADDED tests/generator.test.ts
ADDED tests/neural-release.test.ts
ADDED tests/python/test_neural_audio.py
MODIFIED .gitignore
MODIFIED LICENSE
MODIFIED README.md
MODIFIED docs/ARCHITECTURE.md
MODIFIED docs/AUDIO_PROVENANCE.md
MODIFIED docs/DEPLOYMENT.md
MODIFIED eslint.config.js
MODIFIED index.html
MODIFIED package-lock.json
MODIFIED package.json
MODIFIED public/audio/correction-apple.wav
MODIFIED public/audio/correction-furniture.wav
MODIFIED public/audio/correction-hat.wav
MODIFIED public/audio/correction-market.wav
MODIFIED public/audio/correction-meat.wav
MODIFIED public/audio/correction-oil.wav
MODIFIED public/audio/correction-sea.wav
MODIFIED public/audio/correction-sound.wav
MODIFIED public/audio/correction-tree.wav
MODIFIED public/audio/correction-umbrella.wav
MODIFIED public/audio/first-apple.wav
MODIFIED public/audio/first-furniture.wav
MODIFIED public/audio/first-hat.wav
MODIFIED public/audio/first-market.wav
MODIFIED public/audio/first-meat.wav
MODIFIED public/audio/first-oil.wav
MODIFIED public/audio/first-sea.wav
MODIFIED public/audio/first-sound.wav
MODIFIED public/audio/first-tree.wav
MODIFIED public/audio/first-umbrella.wav
MODIFIED public/audio/intro.wav
MODIFIED public/audio/last-apple.wav
MODIFIED public/audio/last-furniture.wav
MODIFIED public/audio/last-hat.wav
MODIFIED public/audio/last-market.wav
MODIFIED public/audio/last-meat.wav
MODIFIED public/audio/last-oil.wav
MODIFIED public/audio/last-sea.wav
MODIFIED public/audio/last-sound.wav
MODIFIED public/audio/last-tree.wav
MODIFIED public/audio/last-umbrella.wav
MODIFIED public/audio/luck-apple.wav
MODIFIED public/audio/luck-furniture.wav
MODIFIED public/audio/luck-hat.wav
MODIFIED public/audio/luck-market.wav
MODIFIED public/audio/luck-meat.wav
MODIFIED public/audio/luck-oil.wav
MODIFIED public/audio/luck-sea.wav
MODIFIED public/audio/luck-sound.wav
MODIFIED public/audio/luck-tree.wav
MODIFIED public/audio/luck-umbrella.wav
MODIFIED public/audio/manifest.json
MODIFIED public/audio/message-apple.wav
MODIFIED public/audio/message-furniture.wav
MODIFIED public/audio/message-hat.wav
MODIFIED public/audio/message-market.wav
MODIFIED public/audio/message-meat.wav
MODIFIED public/audio/message-oil.wav
MODIFIED public/audio/message-sea.wav
MODIFIED public/audio/message-sound.wav
MODIFIED public/audio/message-tree.wav
MODIFIED public/audio/message-umbrella.wav
MODIFIED public/audio/middle-apple.wav
MODIFIED public/audio/middle-furniture.wav
MODIFIED public/audio/middle-hat.wav
MODIFIED public/audio/middle-market.wav
MODIFIED public/audio/middle-meat.wav
MODIFIED public/audio/middle-oil.wav
MODIFIED public/audio/middle-sea.wav
MODIFIED public/audio/middle-sound.wav
MODIFIED public/audio/middle-tree.wav
MODIFIED public/audio/middle-umbrella.wav
MODIFIED public/audio/mission-apple.wav
MODIFIED public/audio/mission-furniture.wav
MODIFIED public/audio/mission-hat.wav
MODIFIED public/audio/mission-market.wav
MODIFIED public/audio/mission-meat.wav
MODIFIED public/audio/mission-oil.wav
MODIFIED public/audio/mission-sea.wav
MODIFIED public/audio/mission-sound.wav
MODIFIED public/audio/mission-tree.wav
MODIFIED public/audio/mission-umbrella.wav
MODIFIED public/audio/password-apple.wav
MODIFIED public/audio/password-furniture.wav
MODIFIED public/audio/password-hat.wav
MODIFIED public/audio/password-market.wav
MODIFIED public/audio/password-meat.wav
MODIFIED public/audio/password-oil.wav
MODIFIED public/audio/password-sea.wav
MODIFIED public/audio/password-sound.wav
MODIFIED public/audio/password-tree.wav
MODIFIED public/audio/password-umbrella.wav
MODIFIED public/audio/remember-apple.wav
MODIFIED public/audio/remember-furniture.wav
MODIFIED public/audio/remember-hat.wav
MODIFIED public/audio/remember-market.wav
MODIFIED public/audio/remember-meat.wav
MODIFIED public/audio/remember-oil.wav
MODIFIED public/audio/remember-sea.wav
MODIFIED public/audio/remember-sound.wav
MODIFIED public/audio/remember-tree.wav
MODIFIED public/audio/remember-umbrella.wav
MODIFIED public/audio/repeat-apple.wav
MODIFIED public/audio/repeat-furniture.wav
MODIFIED public/audio/repeat-hat.wav
MODIFIED public/audio/repeat-market.wav
MODIFIED public/audio/repeat-meat.wav
MODIFIED public/audio/repeat-oil.wav
MODIFIED public/audio/repeat-sea.wav
MODIFIED public/audio/repeat-sound.wav
MODIFIED public/audio/repeat-tree.wav
MODIFIED public/audio/repeat-umbrella.wav
MODIFIED scripts/generate_audio.py
MODIFIED src/App.tsx
MODIFIED tests/App.test.tsx
MODIFIED tests/assets.test.ts
MODIFIED tests/browser/game.spec.ts
MODIFIED tests/browser/ui.spec.ts
USER INPUT .agent/ACCEPTANCE-v0.1.1.md
USER INPUT .agent/TASK-v0.1.1.md
Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+71
View File
@@ -0,0 +1,71 @@
"""생성기 함수를 재사용하지 않는 v0.1.1 인수 검사: 원문·이전 해시·PCM·FFmpeg."""
from array import array
import hashlib
import json
import math
from pathlib import Path
import subprocess
import sys
import wave
root = Path(__file__).resolve().parents[2]
evidence = root / ".agent/evidence-v0.1.1"
manifest = json.loads((root / "public/audio/manifest.json").read_text())
baseline = json.loads((evidence / "baseline.json").read_text())
old = {entry["file"]: entry for entry in baseline["audio"]["files"]}
expected = json.loads(subprocess.check_output([
"node", "--experimental-strip-types", "--input-type=module", "-e",
"import {INTRO,PATTERNS,WORDS,renderSentence} from './src/content.ts'; "
"console.log(JSON.stringify([{file:'intro.wav',text:INTRO},"
"...PATTERNS.flatMap(p=>WORDS.map(w=>({file:p.id+'-'+w.id+'.wav',text:renderSentence(p,w)})))]));"
], cwd=root, text=True))
assert manifest["version"] == "0.1.1"
assert manifest["provider"] == "Microsoft Edge online TTS"
assert manifest["voice"] == "ko-KR-HyunsuMultilingualNeural"
assert manifest["rate"] == "-6%" and manifest["pitch"] == "-4Hz"
assert manifest["toolVersions"]["edge-tts"] == "7.3.1"
assert [{"file": e["file"], "text": e["text"]} for e in manifest["files"]] == expected
assert len(expected) == 101
assert {p.name for p in (root / "public/audio").iterdir()} == {e["file"] for e in expected} | {"manifest.json"}
rows = []
for entry in manifest["files"]:
path = root / "public/audio" / entry["file"]
data = path.read_bytes()
digest = hashlib.sha256(data).hexdigest()
assert digest == entry["sha256"] and digest != old[entry["file"]]["sha256"]
assert len(data) == entry["bytes"]
with wave.open(str(path), "rb") as stream:
assert (stream.getframerate(), stream.getnchannels(), stream.getsampwidth(), stream.getcomptype()) == (24000, 1, 2, "NONE")
duration = stream.getnframes()/24000
assert 1 <= duration <= 20 and duration == entry["duration"]
samples = array("h", stream.readframes(stream.getnframes()))
if sys.byteorder != "little":
samples.byteswap()
rms = math.sqrt(sum(x*x for x in samples)/len(samples))/32768
peak = max(abs(x) for x in samples)/32768
assert rms > 100/32768 and peak < 32767/32768
assert peak/rms*0.03*2 < 0.8
assert abs(entry["rms"]-rms) < 1e-12 and abs(entry["peak"]-peak) < 1e-12
probe = json.loads(subprocess.check_output([
"ffprobe", "-v", "error", "-show_entries",
"stream=codec_name,sample_fmt,sample_rate,channels,bits_per_sample,duration", "-of", "json", str(path)
], text=True))["streams"]
assert len(probe) == 1
stream = probe[0]
assert (stream["codec_name"], stream["sample_fmt"], stream["sample_rate"], stream["channels"], stream["bits_per_sample"]) == ("pcm_s16le", "s16", "24000", 1, 16)
assert abs(float(stream["duration"])-duration) < 1e-5
subprocess.run(["ffmpeg", "-v", "error", "-xerror", "-i", str(path), "-f", "null", "-"], check=True, capture_output=True)
rows.append({"file": path.name, "sha256": digest, "bytes": len(data), "duration": duration,
"rms": rms, "peak": peak, "ffprobe": stream, "newVsV01": True, "ffmpegDecoded": True})
print(f"PASS {path.name}: {duration:.3f}s, RMS={rms:.6f}, peak={peak:.6f}", flush=True)
assert len({r["sha256"] for r in rows}) == 101
assert sum(r["bytes"] for r in rows) < 48*1024*1024
for path, digest in baseline["historical"].items():
assert hashlib.sha256((root / path).read_bytes()).hexdigest() == digest, path
summary = {"count": len(rows), "newVsV01": 101, "uniqueHashes": 101, "bytes": sum(r["bytes"] for r in rows),
"durationRange": [min(r["duration"] for r in rows), max(r["duration"] for r in rows)],
"rmsRange": [min(r["rms"] for r in rows), max(r["rms"] for r in rows)],
"peakRange": [min(r["peak"] for r in rows), max(r["peak"] for r in rows)],
"historicalUnchanged": len(baseline["historical"]), "files": rows}
(evidence / "audio-integrity.json").write_text(json.dumps(summary, ensure_ascii=False, indent=2)+"\n")
print(json.dumps({k:v for k,v in summary.items() if k != "files"}, indent=2))
+64
View File
@@ -0,0 +1,64 @@
/* global OfflineAudioContext */
// 실제 Chrome의 WAV 디코더로 101개를 검증한다. 재생·UI 흐름은 전체
// Playwright suite가 별도 담당하며 이 인수 검사는 모의 AudioContext를 쓰지 않는다.
import assert from 'node:assert/strict';
import { writeFileSync } from 'node:fs';
import { spawn } from 'node:child_process';
import { chromium } from '@playwright/test';
const server = spawn(process.execPath, ['node_modules/vite/bin/vite.js', 'preview', '--host', '127.0.0.1', '--port', '4174', '--strictPort'], { stdio: 'ignore' });
const base = 'http://127.0.0.1:4174';
let browser;
try {
for (let i = 0; ; i++) {
try { if ((await fetch(base)).ok) break; } catch { /* localhost 준비만 기다린다. */ }
assert(i < 100, 'preview startup failed');
await new Promise(resolve => setTimeout(resolve, 100));
}
browser = await chromium.launch({ executablePath: '/usr/bin/google-chrome', chromiumSandbox: true });
const sandbox = await browser.newPage();
await sandbox.goto('chrome://sandbox');
const sandboxStatus = await sandbox.locator('body').innerText();
console.log('SANDBOX STATUS\n' + sandboxStatus);
assert.match(sandboxStatus, /Seccomp-BPF sandbox\s+Yes/);
await sandbox.close();
const page = await browser.newPage();
const external = [], errors = [];
page.on('request', r => { if (!r.url().startsWith(base + '/')) external.push(r.url()); });
page.on('pageerror', e => errors.push(e.message));
await page.goto(base);
assert.equal(await page.title(), '단어를 맞춰라 · Find-Word v0.1.1');
assert.equal(await page.locator('.version').innerText(), 'v0.1.1');
const result = await page.evaluate(async () => {
const manifest = await (await fetch('/audio/manifest.json')).json();
const context = new OfflineAudioContext(1, 1, 24000);
const rows = [];
for (const entry of manifest.files) {
const response = await fetch('/audio/' + entry.file);
if (!response.ok) throw Error(entry.file + ': HTTP failure');
const bytes = await response.arrayBuffer();
const digest = Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256', bytes)), b => b.toString(16).padStart(2, '0')).join('');
if (digest !== entry.sha256 || bytes.byteLength !== entry.bytes) throw Error(entry.file + ': integrity failure');
const buffer = await context.decodeAudioData(bytes);
let power = 0, peak = 0;
for (const x of buffer.getChannelData(0)) { power += x*x; peak = Math.max(peak, Math.abs(x)); }
if (buffer.sampleRate !== 24000 || buffer.numberOfChannels !== 1 || Math.abs(buffer.duration-entry.duration)>1e-9)
throw Error(entry.file + ': decode format/duration mismatch');
const rms = Math.sqrt(power/buffer.length);
if (rms <= 100/32768 || peak >= 32767/32768) throw Error(entry.file + ': signal failure');
rows.push({ file: entry.file, sha256: digest, bytes: entry.bytes, sampleRate: buffer.sampleRate,
channels: buffer.numberOfChannels, duration: buffer.duration, rms, peak });
}
return { version: manifest.version, voice: manifest.voice, files: rows };
});
assert.equal(result.version, '0.1.1');
assert.equal(result.voice, 'ko-KR-HyunsuMultilingualNeural');
assert.equal(result.files.length, 101);
assert.deepEqual(external, []);
assert.deepEqual(errors, []);
writeFileSync('.agent/evidence-v0.1.1/browser-audio-integrity.json', JSON.stringify({ chrome: browser.version(), sandboxStatus, external, errors, ...result }, null, 2)+'\n');
console.log('PASS: sandboxed Chrome decoded 101/101 WAVs at 24kHz mono; hashes, bytes, duration, RMS, peak verified; external requests=0, JS errors=0.');
} finally {
await browser?.close();
server.kill('SIGTERM');
}
+2
View File
@@ -5,3 +5,5 @@ dist/
test-results/
playwright-report/
*.local
.venv-audio/
__pycache__/
+7 -2
View File
@@ -1,9 +1,14 @@
Find-Word v0.1
Find-Word v0.1.1
Private / proprietary. All rights reserved.
No license is granted to use, copy, modify, publish, distribute, sublicense,
or sell the original project code, documentation, or assets without prior
or sell the original project code or documentation without prior
written permission from the respective rights holders.
Third-party components remain subject to their own licenses. Their notices
are reproduced in THIRD_PARTY_NOTICES.md and accompany the distribution.
This project does not claim exclusive rights to generated speech.
Provider terms and any third-party rights remain applicable to generated audio;
the project notice does not grant or warrant rights in that output.
See docs/AUDIO_PROVENANCE.md.
+29 -5
View File
@@ -1,4 +1,4 @@
# 단어를 맞춰라 · Find-Word v0.1
# 단어를 맞춰라 · Find-Word v0.1.1
소음 속에 숨은 한국어 단어를 듣고 찾는 반응형 웹 게임입니다.
@@ -79,17 +79,41 @@ Chromium sandbox는 기본으로 켭니다. sandbox를 지원하지 않는 격
브라우저 테스트는 기존 `dist/`를 사용하므로 소스 변경 후 먼저 빌드하세요.
실제 음성 재생이 끝나기를 기다려 약 2–3분이 걸립니다. 로컬 4173 포트를
테스트 중에만 열고 종료합니다. 스크린샷은 `.agent/evidence/`에 남습니다.
테스트 중에만 열고 종료합니다. 스크린샷과 101개 WAV의 query URL·해시·디코드
결과는 `test-results/`에 저장합니다. 인수 기록은 실행별 새 evidence 경로에
복사하여 `.agent/evidence-v0.1.1/`의 과거 결과를 보존합니다.
## 음성과 문서
한국어 WAV는 직접 쓴 문장을 로컬 eSpeak NG로 합성했습니다. 환경음은
브라우저에서 고정 seed로 합성합니다. 외부 음원이나 신경망 음성 모델을 사용하지 않습니다.
한국어 WAV 101개는 직접 쓴 문장을 Microsoft Edge online TTS의
`ko-KR-HyunsuMultilingualNeural`로 새로 생성했습니다. edge-tts **7.3.1**,
rate `-6%`, pitch `-4Hz`이며 FFmpeg로 **24kHz mono PCM16**으로 변환합니다.
생성 시 네트워크가 필요하며 앱은 저장된 WAV만 재생합니다. 환경음은 브라우저에서
고정 seed로 합성합니다. 생성 음성의 독점 권리를 주장하지 않습니다.
intro와 목표 WAV는 모두 `/audio/파일명.wav?v=0.1.1`로 요청합니다.
`src/audio/assets.ts`의 자산 버전 한 곳을 사용하며, 같은 파일명으로 음성을
교체할 때 이 값을 갱신해 기존 7일 캐시와 구분합니다. 제품 버전은 0.1.1입니다.
Linux에서 Python 3.11 이상과 FFmpeg를 준비한 뒤 다음 명령을 사용합니다.
클라이언트 버전을 고정해도 원격 모델 변경으로 동일 바이트 재생성은 보장하지 않습니다.
```bash
python3 -m venv .venv-audio
.venv-audio/bin/python -m pip install -r requirements-audio.txt
.venv-audio/bin/python -m pip check
npm run audio:generate
```
고정 venv의 Python이 101개 모두 임시 생성·검증하고 디렉터리를 원자 교체합니다.
요청별 60초 제한과 최대 3회 시도를 적용하며, 실패 시 기존 자산을 보존합니다.
청취 샘플: [안내](public/audio/intro.wav), [행운의 사과](public/audio/luck-apple.wav).
생성 방법, 도구 라이선스, 합성 음질의 한계는 [AUDIO_PROVENANCE.md](docs/AUDIO_PROVENANCE.md)를
참고하세요. 실제 음량은 출력 장치에 따라 달라지며 표기 dB는 디지털 상대값입니다.
- [설계와 상태 전이](docs/ARCHITECTURE.md)
- [Neo를 위한 정적 배포 안내](docs/DEPLOYMENT.md)
- [RED/GREEN 및 실제 검증 결과](.agent/RESULT.md)
- [v0.1.1 RED/GREEN 및 실제 검증 결과](.agent/RESULT-v0.1.1.md)
- [v0.1 역사 기록](.agent/RESULT.md)
이번 작업에서는 서버 배포와 Git commit/push를 실행하지 않습니다.
+11 -1
View File
@@ -1,4 +1,4 @@
# 설계
# Find-Word v0.1.1 설계
## 데이터와 출제
@@ -67,6 +67,11 @@ Promise를 무시한다. 질문과 보기는 재생 완료 후 DOM에 생성되
## 오디오
101개 저장 WAV는 edge-tts 7.3.1의 `ko-KR-HyunsuMultilingualNeural`로
빌드 전에 생성한다. 24kHz mono PCM16이며 원문·도구·해시는 manifest에 남긴다.
생성기는 임시 디렉터리에서 전체 검증 후 원자 교체한다. 생성 절차는
[AUDIO_PROVENANCE](AUDIO_PROVENANCE.md)에 있으며 앱은 provider에 연결하지 않는다.
`src/audio/dsp.ts`는 순수 수치 함수이며 장치가 없어도 테스트할 수 있다.
정수 seed 잡음에 저역 통과 필터, 사인파, 진폭 변조를 조합하고 양 끝을 페이드한다.
8개 프리셋은 실제 현장 녹음이 아니라 환경을 추상적으로 표현한 합성 신호다.
@@ -76,6 +81,11 @@ Promise를 무시한다. 질문과 보기는 재생 완료 후 DOM에 생성되
RMS를 0.03으로 정규화한다. `gain = 10^(dB/20)`으로 목표 gain을 지정한다.
시간별·주파수별 청감이나 물리적 dB SPL을 보장하는 수치는 아니다.
`src/audio/assets.ts`는 음성 자산 버전과 URL 생성을 한 곳에서 관리한다.
intro와 목표 100개 모두 `?v=0.1.1`을 붙여 동일 파일명에 남은 이전 캐시를
피한다. 파일을 다시 생성하면 제품 버전 유지 여부와 관계없이 자산 버전을
갱신한다. 버전 확인을 위한 외부 요청이나 런타임 manifest 요청은 없다.
```text
배경 BufferSource → 배경 Gain (1, 시작/끝 fade) ─┐
목표 BufferSource → 음성 Gain (10^(dB/20)) ─────┼→ master Gain → destination
+84 -64
View File
@@ -1,83 +1,103 @@
# 오디오 출처와 재현
# Find-Word v0.1.1 오디오 출처와 재현
## 포함 자산
## 포함 자산과 생성 설정
| 대상 | 생성 방식 | 원문/설정 | 배포 방식 |
| --- | --- | --- | --- |
| `public/audio/intro.wav` | 로컬 eSpeak NG 한국어 포먼트 합성 | `src/content.ts`의 INTRO | PCM WAV |
| 목표 음성 100개 | 같은 로컬 엔진 | 10 패턴 × 10 단어 | PCM WAV |
| 길거리·쇼핑몰·극장·백화점·시장·지하철·카페·비 오는 거리 | 직접 작성한 결정론적 DSP | `ENVIRONMENTS`, 고정 seed | 브라우저 메모리에서 합성 |
| 화면 파형·S 캐릭터 | 직접 작성한 CSS | `App.tsx`, `styles.css` | CSS, 외부 이미지 없음 |
| `public/audio/intro.wav` | Microsoft Edge online TTS neural 음성 | `src/content.ts`의 INTRO | 24kHz mono PCM16 WAV |
| 목표 음성 100개 | 같은 provider·voice | 10 패턴 × 10 단어, `renderSentence` | 같은 WAV |
| 8개 배경 환경 | 직접 작성한 결정론적 DSP | `ENVIRONMENTS`, 고정 seed | 브라우저 메모리에서 합성 |
| 화면 파형·S 캐릭터 | 직접 작성한 CSS | `App.tsx`, `styles.css` | CSS |
모든 한국어 문장은 이번 앱을 위해 직접 작성했다. 다른 사람의 녹음, 노래,
샘플 라이브러리, 음성 복제, 신경망 모델을 포함하지 않는다. 웃음도 INTRO의
‘으하하하~~’ 문자열을 동일 엔진으로 합성한 것이다. 효과를 위해 타인 음원을
다운로드하지 않았다. 런타임에 speechSynthesis 또는 네트워크 TTS도 호출하지 않는다.
voice는 **`ko-KR-HyunsuMultilingualNeural`**, rate는 **`-6%`**, pitch는
**`-4Hz`**, 생성 클라이언트는 **edge-tts 7.3.1**이다. 직접 작성한 한국어
문장을 온라인 provider에 보내 MP3 응답을 받은 뒤 FFmpeg로 PCM을 만든다.
음성 복제나 사람의 녹음 샘플을 사용하지 않는다. 웃음은 INTRO의 ‘으하하하~~’를
같은 voice로 합성한다. 앱은 저장한 WAV만 같은 출처에서 가져오며 런타임 외부
TTS/API, speechSynthesis, 인증정보가 필요하지 않다.
WAV는 16kHz, mono, signed 16-bit little-endian PCM이다. 101개 합계는
**20,497,222바이트**다. 파일별 원문·바이트 수·SHA-256은
`public/audio/manifest.json`에 있다. 생성 시 실행 도구에서 읽은 eSpeak NG 1.51,
FFmpeg 6.1.1-3ubuntu5의 실제 버전도 기록했다. `tests/assets.test.ts`는 원문 대응, PCM
포맷, 비무음 신호, 20MiB 이내 크기, gain 적용 후 피크 여유를 검사한다.
빌드 마지막에는 `dist/audio` 파일의 해시도 확인한다.
청취 연산 변경에 맞춰 101개 WAV와 manifest를 모두 재생성했다. 정답과 경쟁
단어는 `renderSentence`로 채우며, 순서·반복·정정·조건·방향 단서가 실제 음성에 들어간다.
청취용 샘플은 [intro.wav](../public/audio/intro.wav)와
[luck-apple.wav](../public/audio/luck-apple.wav)이다. 101개 전체 생성 결과의
크기·길이 범위와 독립 검증은 [v0.1.1 RESULT](../.agent/RESULT-v0.1.1.md)에 기록한다.
`public/audio/manifest.json`은 version, provider, voice, rate, pitch, sampleRate,
생성 시각, 실측 edge-tts/FFmpeg 버전, 파일별 원문·SHA-256·bytes·duration·RMS·peak를 담는다.
## 사용 도구와 라이선스
## 설치와 생성
- [eSpeak NG 공식 저장소](https://github.com/espeak-ng/espeak-ng): GPL-3.0-or-later.
이번에는 Ubuntu 24.04 패키지 `1.51+dfsg-12build1`, `ko` 포먼트 음성을 사용했다.
[공식 언어 목록](https://github.com/espeak-ng/espeak-ng/blob/master/docs/languages.md)에 한국어가 있다.
- [FFmpeg 공식 라이선스 안내](https://ffmpeg.org/legal.html): 빌드 구성에 따라
LGPL/GPL. 생성 과정에서 PCM 리샘플링만 사용했으며 실행 파일을 배포하지 않는다.
- 합성 엔진의 프로그램 라이선스와 그 출력물은 구분한다.
[GPLv3 §2](https://www.gnu.org/licenses/gpl-3.0.html#section2) 및
[GNU 출력물 설명](https://www.gnu.org/licenses/gpl-faq.html#GPLOutput)에 따르면
출력이 그 프로그램을 바탕으로 한 저작물인 경우에만 프로그램 라이선스가
출력에 적용된다. 이 작업의 산출물은 직접 작성한 텍스트의 포먼트 합성 파형이며,
프로그램 코드·외부 녹음·모델을 포함하지 않는 자체 생성 오디오로 취급한다.
- 엔진·라이브러리·다운로드한 Debian 패키지는 `.cache/`에서만 생성 도구로
사용하며 Git 대상과 `dist/`에 들어가지 않는다. 별도 외부 음원 라이선스는 없다.
프로젝트 자체의 소스·문서·자체 생성 자산은 private / all-rights-reserved다.
[루트 LICENSE](../LICENSE)를 따른다. 별도로 번들에 포함되는 React, ReactDOM,
scheduler의 MIT 전문은 [THIRD_PARTY_NOTICES.md](../THIRD_PARTY_NOTICES.md)에
있으며 `dist/THIRD_PARTY_NOTICES.md`로 함께 배포한다.
## 생성 절차
일반적인 Ubuntu 개발 환경에는 `espeak-ng`, `ffmpeg`, Python 3, Node.js가
필요하다. **이미 포함된 WAV로 빌드·실행할 때는 이 도구가 필요 없다.**
생성 환경은 Linux (기존 디렉터리 교체에 `renameat2(RENAME_EXCHANGE)` 필요),
Python 3.11 이상, FFmpeg, Node.js 22.22.2 이상이다. **이미 포함된 WAV를
빌드·실행할 때는 Python/FFmpeg/provider 연결이 필요 없다.** 생성기 계약 테스트는
Python과 FFmpeg를 사용하되 네트워크 없이 동작한다.
```bash
python3 -m venv .venv-audio
.venv-audio/bin/python -m pip install -r requirements-audio.txt
.venv-audio/bin/python -m pip check
npm run audio:generate
npm test -- tests/assets.test.ts
npm test
npm run build
```
현재 작업에서는 시스템 설치 없이 다음 명령으로 worktree 내부에 도구를 풀었다.
이 명령은 문서화용이며 서버에서 실행한 이력이 없다.
`audio:generate`는 `.venv-audio/bin/python scripts/generate_audio.py`로 고정되어
전역 Python으로 대체되지 않는다. `requirements-audio.txt`는 edge-tts==7.3.1과
전이 의존성 버전을 고정한다. 생성기는 실제 설치 버전을 조회하고 7.3.1이 아니면
외부 요청 전에 실패한다. `.venv-audio/`는 Git과 배포물에서 제외한다.
```bash
mkdir -p .cache/espeak
cd .cache/espeak
apt download espeak-ng espeak-ng-data libespeak-ng1 libpcaudio0 libsonic0
for pkg in *.deb; do dpkg-deb -x "$pkg" root; done
cd ../..
npm run audio:generate
```
원문을 Node type stripping으로 앱 데이터에서 읽고, 101개 모두 같은 파일시스템의
`public/.audio-stage-*/`에 순차 생성한다. 각 provider 요청은 최대 60초, 최대
3회 시도이며 실패 사이 1초/2초를 기다린다. FFmpeg도 60초 제한이 있다.
재시도 전 불완전 MP3를 삭제하고 변환·검증 실패는 즉시 중단한다. 로그에는
파일명·시도 횟수만 남기고 provider stderr/응답·쿠키·인증 헤더를 저장하지 않는다.
`scripts/generate_audio.py`가 시스템 엔진 또는 `.cache/espeak/root/usr`를
자동 선택한다. `ko`, 속도 145, 피치 45, 진폭 100을 고정하고 FFmpeg로 16kHz
PCM을 만든 뒤 Python wave 모듈로 메타데이터 없는 WAV를 쓴다. 런타임 데이터는
Node의 type stripping으로 읽어 텍스트 중복을 피한다. 같은 엔진·버전·플랫폼에서는
해시로 재현 여부를 비교할 수 있다. 다른 버전은 새 출처와 해시를 검토해야 한다.
전체 WAV와 manifest를 검증한 뒤 기존 `public/audio`와 완성 디렉터리를 단일
원자 교환으로 바꾼다. 실패·Ctrl-C는 기존 디렉터리의 바이트를 그대로 보존한다.
원자 교환을 지원하지 않는 파일시스템에서는 실패하며 비원자 방식으로 우회하지 않는다.
성공 후 이전 자산과 임시 MP3를 정리한다. 강제 종료(SIGKILL)·전원 손실 때는
숨김 staging 폴더가 남을 수 있으나 공개 디렉터리는 교환 전 또는 후의 전체 집합이다.
이는 전원 손실 시 저장장치 내구성 보장을 뜻하지 않는다.
## 음량·품질 한계
고정 클라이언트와 설정으로 **생성 절차**를 재현할 수 있다. 원격 모델·서비스 버전은
고정할 수 없어 재생성 WAV의 바이트 동일성은 보장하지 않는다. 새 실행의 manifest를
검토해야 한다. 빌드는 이미 생성한 WAV의 해시를 보존하고 101개 모두 포함됐는지 확인한다.
보이스와 배경은 같은 디지털 RMS로 정규화되고 음성 경로만 dB gain을 적용한다.
안내의 gain은 1.8에서 0.12로 감소한다. 기본 전체 음량은 35%이다.
물리적 음압을 측정하거나 장치 출력을 보정하지 않는다.
## 레벨 처리와 검증
포먼트 합성 특성상 한국어 발음·억양과 웃음이 기계적으로 들린다. 배경도 실제
장소 녹음처럼 세밀하지 않다. 객관식의 자모 차이와 단어 친숙도, 발음의 자연스러움은
검수자가 직접 들어 평가해야 한다. 현재 단계 수치는 임상 검증이나 청력 판정용이 아니다.
MP3를 24kHz mono signed 16-bit little-endian PCM으로 디코드한다. 파일 전체에
동일한 선형 gain을 적용해 RMS 0.10을 목표로 하며 증폭은 최대 2배, peak는
0.89로 제한한다. 동적 압축·노이즈 게이트·침묵 제거·시간 변형은 하지 않는다.
원래 신호의 자음과 억양을 보존하면서 파일 간 레벨 차이와 피크를 완화한다.
생성기와 독립 자산 테스트는 101개 파일의 원문·집합·SHA-256·bytes·duration,
24kHz mono PCM16, 1–20초 길이, RMS > 100/32768, full-scale 미도달,
총 48MiB 미만을 검사한다. 런타임 RMS 0.03과 최대 +6dB에서도 peak < 0.8을
요구한다. 기존 앱은 Web Audio에서 배경·음성을 RMS 정규화한 뒤 상대 SNR을 적용한다.
물리적 음압이나 주파수별 청감을 보정한 값은 아니다.
## 도구 라이선스와 서비스 조건
- [edge-tts 7.3.1 LICENSE](https://github.com/rany2/edge-tts/blob/7.3.1/LICENSE):
대부분의 코드에 LGPLv3, `srt_composer.py`에만 MIT가 적용된다.
[공식 프로젝트](https://github.com/rany2/edge-tts)는 Microsoft Edge의 온라인
TTS를 이용하는 클라이언트다. 클라이언트 라이선스가 provider 사용·음성 출력의
재배포 권한을 대신 부여하지 않는다. 이 프로젝트는 클라이언트/모델을 번들하지 않는다.
- [FFmpeg 공식 라이선스](https://ffmpeg.org/legal.html): 빌드 옵션에 따라 LGPL/GPL이
적용된다. 실제 사용 버전은 manifest에 남기며 실행 파일은 배포하지 않는다.
- [Microsoft Services Agreement](https://www.microsoft.com/en-us/servicesagreement)의
AI Services 등 해당 서비스 조건은 도구의 오픈소스 라이선스와 별개다.
위 문서 §13(s)(vi)는 출력의 권리·사용 가능성을 이용자가 판단하도록 설명한다.
API 키 없이 호출된다는 사실이 상업 사용·재배포의 포괄적 허락이나 SLA를 뜻하지 않는다.
배포자는 자신의 이용 상황에 적용되는 최신 조건을 확인해야 한다.
- 프로젝트는 생성 음성 자체에 **독점 권리를 주장하지 않는다**. [LICENSE](../LICENSE)의
소스·문서 권리 유보와 provider 및 제3자의 권리는 구분한다. 런타임 React,
ReactDOM, scheduler의 MIT 전문은 [THIRD_PARTY_NOTICES.md](../THIRD_PARTY_NOTICES.md)에 있다.
문서 확인일: 2026-10-14 UTC. provider의 음성 목록, rate/pitch 지원, 가용성,
접근 제한, 조건은 바뀔 수 있다. 온라인 생성이 중단되어도 포함된 WAV의 빌드·재생에는
영향이 없다. 실패 시 다른 voice로 자동 대체하지 않는다.
## 청감과 평가의 한계
자동 검증은 PCM 신호·무결성·재생 흐름을 확인한다. 한국어 발음, 유사 자모의
구분, 웃음의 자연스러움과 실제 사용자의 난이도는 청취 평가가 필요하다.
대표 샘플과 게임 내 소음 혼합 상태를 직접 들어 인수 판단한다. 배경은 장소를
추상화한 합성 신호다. 이 게임의 수치는 임상 검증·치료·청력 판정용이 아니다.
+13 -8
View File
@@ -1,4 +1,4 @@
# 정적 배포 인계
# Find-Word v0.1.1 정적 배포 인계
이 문서는 **Neo가 검토 후 수행할 절차**다. Codex는 서버, DNS, 인증정보에
접근하지 않았고 배포·서비스 생성·Git commit/push도 하지 않았다.
@@ -7,7 +7,7 @@
Node.js 최소 **22.22.2** (`>=22.22.2`)의 지원 LTS 환경에서 `npm ci`, `npm run lint`, `npm test`,
`npm run build`를 실행한다. `dist/` 전체를 하나의 릴리스로 전달한다.
`dist/audio/`의 WAV 101개와 manifest가 반드시 포함되어야 한다. 런타임은
`dist/audio/`의 24kHz neural WAV 101개와 version 0.1.1 manifest가 반드시 포함되어야 한다. 런타임은
Nginx 정적 파일만 필요하며 Node 서버·TTS 엔진·DB·환경변수·API 키는 필요 없다.
잠긴 jsdom 계열 의존성 때문에 24.x는 24.15.0 이상, 26.x는 26.0.0 이상이어야 한다.
브라우저 검증의 Chromium sandbox는 기본 활성화다. sandbox를 지원하지 않는
@@ -15,6 +15,8 @@ Nginx 정적 파일만 필요하며 Node 서버·TTS 엔진·DB·환경변수·A
Canonical repository는 [OZ-Group/Find-Word](https://source.ibit.kr/OZ-Group/Find-Word)다.
프로젝트 자체는 private / all-rights-reserved이며 [LICENSE](../LICENSE)를 따른다.
생성 음성은 프로젝트의 독점 권리 주장 대상이 아니며 provider 조건은
[AUDIO_PROVENANCE](AUDIO_PROVENANCE.md)에 기록한다.
React, ReactDOM, scheduler의 MIT 전문을 담은 `dist/THIRD_PARTY_NOTICES.md`도
반드시 배포한다. `build` 검증기는 고지 파일이 없거나 축약·변조되면 실패한다.
@@ -46,11 +48,11 @@ server {
expires 1y;
}
# 음성 파일명은 재생성해도 같으므로 재검증한다. 누락 시 index.html 대신
# 404를 반환해야 앱이 명확한 음성 로드 오류와 재시도를 제공할 수 있다.
# 앱은 intro·목표 모두 같은 자산 버전 query를 붙여 이전 캐시와 구분한다.
# $uri는 query를 제외한 실제 WAV 경로다. 누락 시 index.html 대신 404로 응답한다.
location /audio/ {
try_files $uri =404;
expires -1;
expires 7d;
}
# SPA의 직접 진입·새로고침을 index.html로 받되 HTML은 재검증한다.
@@ -65,10 +67,13 @@ server {
1. 서버에 적용하기 전 `nginx -t`, 기존 서비스 충돌, 파일 읽기 권한을 확인한다.
2. TLS/HTTPS와 DNS를 운영자가 확인한다. 실제 도메인에서 시작 후 음성이 들리는지 확인한다.
3. `audio/intro.wav`와 목표 WAV가 정상 응답하고 존재하지 않는 오디오는 404인지 확인한다.
3. `audio/intro.wav?v=0.1.1`와 목표 WAV의 같은 버전 query가 정상 응답하고
존재하지 않는 오디오는 query가 있어도 404인지 확인한다.
4. 모바일 Safari/Chrome, 데스크톱에서 음량·중단·다시 듣기·10문제 완주를 직접 확인한다.
5. 원자적으로 릴리스 디렉터리를 전환하고 이전 디렉터리를 보관해 되돌릴 수 있게 한다.
오프라인 캐시를 제공하는 PWA는 아니다. 정적 자산의 최초 로드에는 해당 서버
연결이 필요하다. 페이지·오디오 캐시가 서로 다른 버전으로 섞이지 않게 HTML과
음성의 재검증 정책을 유지한다.
연결이 필요하다. HTML은 재검증하고, 오디오는 URL의 자산 버전으로 구분한다.
같은 파일명으로 WAV를 교체할 때 `src/audio/assets.ts`의 `AUDIO_ASSET_VERSION`도
갱신한다. 제품 버전을 유지하는 음성 수정에서도 새 자산 버전이 필요하다.
이 query는 로컬 정적 파일 요청에만 사용하며 런타임 외부 요청을 추가하지 않는다.
+1
View File
@@ -11,6 +11,7 @@ export default tseslint.config(
"dist/**",
"node_modules/**",
".cache/**",
".venv-audio/**",
"test-results/**",
"playwright-report/**",
],
+1 -1
View File
@@ -10,7 +10,7 @@
name="description"
content="소음 속 작은 한국어 단어를 찾는 청각적 주의·식별 게임. 에스와 함께 나만의 속도로 소리를 탐험하세요."
/>
<title>단어를 맞춰라 · Find-Word v0.1</title>
<title>단어를 맞춰라 · Find-Word v0.1.1</title>
</head>
<body>
<div id="root"></div>
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "find-word",
"version": "0.1.0",
"version": "0.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "find-word",
"version": "0.1.0",
"version": "0.1.1",
"dependencies": {
"react": "^19.3.0",
"react-dom": "^19.3.0"
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "find-word",
"private": true,
"version": "0.1.0",
"version": "0.1.1",
"type": "module",
"engines": {
"node": ">=22.22.2"
@@ -13,7 +13,7 @@
"test:watch": "vitest",
"build": "tsc --noEmit && vite build && node scripts/check-build.mjs",
"preview": "vite preview --host 127.0.0.1",
"audio:generate": "python3 scripts/generate_audio.py",
"audio:generate": ".venv-audio/bin/python scripts/generate_audio.py",
"test:browser": "playwright test"
},
"dependencies": {
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More