Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
812540c743 | ||
|
|
c92660b514 | ||
|
|
a92b2ba1e9 |
@@ -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 미실행
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# Find-Word v0.2.3 수용 기준
|
||||||
|
|
||||||
|
## 버전·문서
|
||||||
|
|
||||||
|
- [ ] package.json/package-lock.json/index.html/UI/README가 `0.2.3`이다.
|
||||||
|
- [ ] `CHANGELOG.md`가 존재하고 v0.2.3의 모든 요구사항·오류 수정·자산·검증 변경을 설명한다.
|
||||||
|
- [ ] 정확한 `Designed by OZ at Heat-T Medical Inc.`를 보존한다.
|
||||||
|
- [ ] README, ARCHITECTURE, DEPLOYMENT, 오디오 provenance가 새 동작과 일치한다.
|
||||||
|
- [ ] 직접 변경한 모듈·함수·클래스·핵심 변수/매개변수·비자명한 로직에 목적 중심의 상세 한국어 주석이 있다.
|
||||||
|
|
||||||
|
## 3문항·난이도
|
||||||
|
|
||||||
|
- [ ] createQuestions는 라운드당 정확히 3개의 서로 다른 문제를 반환한다.
|
||||||
|
- [ ] 시작 난이도 1~5를 명시적으로 받으며 3문항이 모두 같은 level/db로 생성된다.
|
||||||
|
- [ ] 정상 완료 후 다음 단계 3문항을 시작할 수 있고 5단계 경계를 넘지 않는다.
|
||||||
|
- [ ] 진행률, 안내문, 결과 분모에 하드코딩된 10이 남지 않는다.
|
||||||
|
- [ ] mixed 모드가 3문항에서도 choice와 text를 모두 포함한다.
|
||||||
|
|
||||||
|
## 수준/SNR 직접 조절
|
||||||
|
|
||||||
|
- [ ] 시작 화면에서 시작 난이도 1~5를 선택할 수 있다.
|
||||||
|
- [ ] 사용자가 배경 대비 목표 음성 SNR dB를 직접 조절할 수 있다.
|
||||||
|
- [ ] 허용 범위 밖·NaN 값은 안전한 범위/기본값으로 정규화한다.
|
||||||
|
- [ ] 변경 값은 현재 문제의 재청취와 남은 라운드 문항에 일관되게 적용된다.
|
||||||
|
- [ ] 화면에 양/0/음수 dB 의미와 현재 값을 정확히 설명한다.
|
||||||
|
|
||||||
|
## 중도 종료
|
||||||
|
|
||||||
|
- [ ] loading/playing/answer/feedback 어느 단계에서도 종료할 수 있다.
|
||||||
|
- [ ] 종료 즉시 fetch/Web Audio source/timer가 취소되고 늦은 완료 이벤트가 상태를 되살리지 않는다.
|
||||||
|
- [ ] 중도 종료 결과가 정답 수/응답 수를 표시하고 무응답을 오답으로 세지 않는다.
|
||||||
|
- [ ] 결과에서 초기 화면으로 돌아가며 새 라운드에 이전 답·오디오·난이도 override가 새지 않는다.
|
||||||
|
|
||||||
|
## 실제 배경음
|
||||||
|
|
||||||
|
- [ ] 8개 Environment 각각 고유 same-origin 정적 WAV URL을 가진다.
|
||||||
|
- [ ] 정확히 8개 실제 현장 녹음 WAV가 빌드에 포함된다.
|
||||||
|
- [ ] 8개 모두 24,000Hz mono PCM16이며 non-silent이고 hash가 서로 다르다.
|
||||||
|
- [ ] manifest/provenance에 environment id, 표시 이름, source page/direct URL, creator, license, attribution, conversion, source SHA-256, output SHA-256, bytes, duration, RMS, peak가 있다.
|
||||||
|
- [ ] 라이선스가 수정·공개 재배포를 허용하며 attribution/notice가 dist에도 포함된다.
|
||||||
|
- [ ] 실제 엔진은 procedural synth가 아니라 선택한 environment 파일을 fetch/decode/loop한다.
|
||||||
|
- [ ] 404/decode/timeout/abort 오류가 복구 가능한 한국어 메시지로 처리된다.
|
||||||
|
- [ ] 배경과 목표는 각각 RMS 정규화 후 `gain = 10^(dB/20)`의 상대 비율을 사용하고 clipping headroom을 유지한다.
|
||||||
|
- [ ] 외부 runtime 요청이 0이며 누락 배경/음성 경로는 SPA HTML이 아니라 404다.
|
||||||
|
|
||||||
|
## 회귀·품질
|
||||||
|
|
||||||
|
- [ ] 기존 10개 mechanic/100개 목표 문장/101개 neural voice assets를 보존한다.
|
||||||
|
- [ ] 객관식·주관식·mixed, 채점, 점수, 재청취, IME 보호, 볼륨, 접근성이 동작한다.
|
||||||
|
- [ ] lint/typecheck, unit/component/Python tests, build verifier, npm audit가 통과한다.
|
||||||
|
- [ ] sandboxed system Chrome desktop/mobile browser suite가 실제 목표·배경 WAV를 decode/play한다.
|
||||||
|
- [ ] 브라우저에서 3문항 완료 → 다음 난이도, 시작 난이도 변경, SNR 변경, 재생 중 종료, 답변 후 종료, 초기화 흐름을 검증한다.
|
||||||
|
- [ ] console/page errors, failed requests, 외부 페이지 요청, axe 위반이 0이다.
|
||||||
|
- [ ] desktop/mobile start/game/normal-results/early-exit screenshots를 생성한다.
|
||||||
|
- [ ] 비밀정보 검사 0, production build에 runtime dependency 및 ambience attribution notice가 포함된다.
|
||||||
|
|
||||||
|
## 릴리스
|
||||||
|
|
||||||
|
- [ ] Neo 독립 검증 후 feature branch를 push한다.
|
||||||
|
- [ ] `main` fast-forward merge, annotated tag `v0.2.3`, fresh-clone readback을 완료한다.
|
||||||
|
- [ ] findword.heart-m.com에 commit-addressed release로 원자 배포하고 기존 release를 rollback 대상으로 보존한다.
|
||||||
|
- [ ] 공개 서비스에서 버전, 배경/목표 MIME·hash, cache-busting, 3문항·다음 단계·중도 종료를 실제 Chrome으로 검증한다.
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.3",
|
||||||
|
"policy": {
|
||||||
|
"runtime": "All ambience files are bundled same-origin static assets; no runtime requests to source sites.",
|
||||||
|
"conversion": "Select a representative segment, remove unsuitable intelligible/incidental content where practical, trim, fade for loop safety, downmix, resample and normalize to 24000 Hz mono PCM16 WAV.",
|
||||||
|
"rights": "CC0/public-domain assets retain suggested credits; CC BY and CC BY-SA derivatives retain exact attribution, modification notice and license. The proprietary project does not claim exclusive rights over third-party recordings.",
|
||||||
|
"verified": "All eight approved direct-media files were verified on 2026-10-14 by SHA-256, byte count, ffprobe and full FFmpeg decode. The expected hashes/bytes are immutable release inputs, never learned or updated by the converter.",
|
||||||
|
"durationFields": "directMediaDurationSeconds is ffprobe format.duration of the exact directUrl bytes (including Freesound preview MP3s), not a rounded primary-page recording duration. Output duration and conversion.durationSeconds describe the 12-second WAV excerpt.",
|
||||||
|
"segmentSelection": "selectedSegmentStartSeconds is immutable per-asset release provenance: the start in exact direct-media seconds of the 12-second derivative. The generator reads it without a separate start map, inference or mutation and rejects segments outside directMediaDurationSeconds before conversion.",
|
||||||
|
"privacyScreening": "The mall 36–48s, market 24–36s and cafe 0–12s selections follow Neo's rescan of the hash-pinned sources through scripts/ambience_audio.convert with faster-whisper 1.2.1 tiny multilingual CPU int8, beam_size=5, best_of=5, default VAD and condition_on_previous_text=true. Exact final-WAV screening is recorded in .agent/evidence-v0.2.3/privacy-screening/final-asr.json; the release test requires requiredEmptyPassed=true. The rejected market 60s/cafe 180s attempt is preserved under prior-attempt-market60-cafe180. ASR is only a screening signal, not a verified transcript, proof of absence of speech/music, human listening acceptance or legal/privacy clearance. Supplementary no-VAD evidence is retained and does not override the VAD gate."
|
||||||
|
},
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"environmentId": "street",
|
||||||
|
"displayName": "길거리",
|
||||||
|
"pageUrl": "https://commons.wikimedia.org/wiki/File:Sunday_in_the_city_street_noise2.ogg",
|
||||||
|
"directUrl": "https://upload.wikimedia.org/wikipedia/commons/2/24/Sunday_in_the_city_street_noise2.ogg",
|
||||||
|
"creator": "cori (Cori Samuel)",
|
||||||
|
"license": "Public domain (PD-author)",
|
||||||
|
"licenseUrl": "https://commons.wikimedia.org/wiki/Template:PD-author",
|
||||||
|
"attribution": "Suggested: Sunday, 4th May 2008 5.05pm - sounds outside my window, by cori (Cori Samuel), via Wikimedia Commons; public domain.",
|
||||||
|
"expectedSourceSha256": "0ddb0be7eb3427f781c8268bcbc74b8ad7e1fbf75b9f6966e65274dbe85f3d9d",
|
||||||
|
"sourceBytes": 3414104,
|
||||||
|
"directMediaDurationSeconds": 264.254694,
|
||||||
|
"sourceVerification": {
|
||||||
|
"status": "verified",
|
||||||
|
"dateUtc": "2026-10-14",
|
||||||
|
"method": "SHA-256, byte count, ffprobe format.duration, full FFmpeg decode",
|
||||||
|
"evidence": ".agent/evidence-v0.2.3/source-integrity.json"
|
||||||
|
},
|
||||||
|
"selectedSegmentStartSeconds": 35
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"environmentId": "mall",
|
||||||
|
"displayName": "쇼핑몰",
|
||||||
|
"pageUrl": "https://commons.wikimedia.org/wiki/File:1_minute_at_the_alexa_mall_in_berlin.ogg",
|
||||||
|
"directUrl": "https://upload.wikimedia.org/wikipedia/commons/f/fd/1_minute_at_the_alexa_mall_in_berlin.ogg",
|
||||||
|
"creator": "thore (Thore)",
|
||||||
|
"license": "Public domain (PD-author)",
|
||||||
|
"licenseUrl": "https://commons.wikimedia.org/wiki/Template:PD-author",
|
||||||
|
"attribution": "Suggested: 1 minute at the Alexa mall in Berlin, by thore, via Wikimedia Commons; public domain.",
|
||||||
|
"expectedSourceSha256": "bb066e130e5d665db57cb5f88e820d053c724d8f777b275213998d2074c6529a",
|
||||||
|
"sourceBytes": 1666896,
|
||||||
|
"directMediaDurationSeconds": 60.05551,
|
||||||
|
"sourceVerification": {
|
||||||
|
"status": "verified",
|
||||||
|
"dateUtc": "2026-10-14",
|
||||||
|
"method": "SHA-256, byte count, ffprobe format.duration, full FFmpeg decode",
|
||||||
|
"evidence": ".agent/evidence-v0.2.3/source-integrity.json"
|
||||||
|
},
|
||||||
|
"selectedSegmentStartSeconds": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"environmentId": "theater",
|
||||||
|
"displayName": "극장",
|
||||||
|
"pageUrl": "https://freesound.org/people/ElevatorFan2020/sounds/853576/",
|
||||||
|
"directUrl": "https://cdn.freesound.org/previews/853/853576_14269391-lq.mp3",
|
||||||
|
"creator": "ElevatorFan2020",
|
||||||
|
"license": "CC0 1.0 Universal",
|
||||||
|
"licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
|
||||||
|
"attribution": "Suggested: Crowd Ambience - Theater, by ElevatorFan2020, from Freesound, CC0 1.0.",
|
||||||
|
"expectedSourceSha256": "05c3ece7c088f34700b7610f791c0ad848a24c77be2c32fd1503a78356739a43",
|
||||||
|
"sourceBytes": 1485015,
|
||||||
|
"directMediaDurationSeconds": 176.901224,
|
||||||
|
"sourceVerification": {
|
||||||
|
"status": "verified",
|
||||||
|
"dateUtc": "2026-10-14",
|
||||||
|
"method": "SHA-256, byte count, ffprobe format.duration, full FFmpeg decode",
|
||||||
|
"evidence": ".agent/evidence-v0.2.3/source-integrity.json"
|
||||||
|
},
|
||||||
|
"selectedSegmentStartSeconds": 45
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"environmentId": "department",
|
||||||
|
"displayName": "백화점",
|
||||||
|
"pageUrl": "https://freesound.org/people/icmusic/sounds/268941/",
|
||||||
|
"directUrl": "https://cdn.freesound.org/previews/268/268941_40107-lq.mp3",
|
||||||
|
"creator": "icmusic",
|
||||||
|
"license": "CC0 1.0 Universal",
|
||||||
|
"licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
|
||||||
|
"attribution": "Suggested: US Department store - checkouts, by icmusic, from Freesound, CC0 1.0.",
|
||||||
|
"expectedSourceSha256": "261fda28722fba623483a90b32e7a2ec388c59887f56a5247156b53f1ffb6ccd",
|
||||||
|
"sourceBytes": 2445024,
|
||||||
|
"directMediaDurationSeconds": 292.872,
|
||||||
|
"sourceVerification": {
|
||||||
|
"status": "verified",
|
||||||
|
"dateUtc": "2026-10-14",
|
||||||
|
"method": "SHA-256, byte count, ffprobe format.duration, full FFmpeg decode",
|
||||||
|
"evidence": ".agent/evidence-v0.2.3/source-integrity.json"
|
||||||
|
},
|
||||||
|
"selectedSegmentStartSeconds": 90
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"environmentId": "market",
|
||||||
|
"displayName": "시장",
|
||||||
|
"pageUrl": "https://commons.wikimedia.org/wiki/File:Italia_Palermo_mercato-Ballaro_20161225_122421.ogg",
|
||||||
|
"directUrl": "https://upload.wikimedia.org/wikipedia/commons/e/e8/Italia_Palermo_mercato-Ballaro_20161225_122421.ogg",
|
||||||
|
"creator": "Marie Flutre (Wikimedia user Timflutre)",
|
||||||
|
"license": "CC BY-SA 4.0",
|
||||||
|
"licenseUrl": "https://creativecommons.org/licenses/by-sa/4.0/",
|
||||||
|
"attribution": "Italia Palermo mercato-Ballaro 20161225 122421, by Marie Flutre, CC BY-SA 4.0, via Wikimedia Commons. Modified by excerpting, trimming, fades, normalization, downmixing, resampling and PCM WAV conversion. The derivative audio remains CC BY-SA 4.0.",
|
||||||
|
"expectedSourceSha256": "fc0075dce8ad05b56460c9f18754c27b2021f21f1c780a595ccda648d33c941d",
|
||||||
|
"sourceBytes": 622200,
|
||||||
|
"directMediaDurationSeconds": 76.696961,
|
||||||
|
"sourceVerification": {
|
||||||
|
"status": "verified",
|
||||||
|
"dateUtc": "2026-10-14",
|
||||||
|
"method": "SHA-256, byte count, ffprobe format.duration, full FFmpeg decode",
|
||||||
|
"evidence": ".agent/evidence-v0.2.3/source-integrity.json"
|
||||||
|
},
|
||||||
|
"selectedSegmentStartSeconds": 24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"environmentId": "subway",
|
||||||
|
"displayName": "지하철",
|
||||||
|
"pageUrl": "https://commons.wikimedia.org/wiki/File:TTC_Subway_Line_1_Ambience_-_Museum_to_Union_(Freesound).ogg",
|
||||||
|
"directUrl": "https://upload.wikimedia.org/wikipedia/commons/d/d3/TTC_Subway_Line_1_Ambience_-_Museum_to_Union_%28Freesound%29.ogg",
|
||||||
|
"creator": "PascalHD",
|
||||||
|
"license": "CC BY 4.0",
|
||||||
|
"licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
|
||||||
|
"attribution": "TTC Subway Line 1 Ambience - Museum to Union, by PascalHD, CC BY 4.0, via Wikimedia Commons/Freesound. Modified by excerpting, trimming, fades, normalization, downmixing, resampling and PCM WAV conversion.",
|
||||||
|
"expectedSourceSha256": "41fcf064cde53cef1528fe98721347851e60c070d8ff9f213f354025cf272d4c",
|
||||||
|
"sourceBytes": 3343901,
|
||||||
|
"directMediaDurationSeconds": 425.024,
|
||||||
|
"sourceVerification": {
|
||||||
|
"status": "verified",
|
||||||
|
"dateUtc": "2026-10-14",
|
||||||
|
"method": "SHA-256, byte count, ffprobe format.duration, full FFmpeg decode",
|
||||||
|
"evidence": ".agent/evidence-v0.2.3/source-integrity.json"
|
||||||
|
},
|
||||||
|
"selectedSegmentStartSeconds": 65
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"environmentId": "cafe",
|
||||||
|
"displayName": "카페",
|
||||||
|
"pageUrl": "https://commons.wikimedia.org/wiki/File:Cafe_ambiance.ogg",
|
||||||
|
"directUrl": "https://upload.wikimedia.org/wikipedia/commons/5/54/Cafe_ambiance.ogg",
|
||||||
|
"creator": "Marble Toast",
|
||||||
|
"license": "CC0 1.0 Universal",
|
||||||
|
"licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
|
||||||
|
"attribution": "Suggested: Cafe ambiance, by Marble Toast, via Wikimedia Commons, CC0 1.0.",
|
||||||
|
"expectedSourceSha256": "6360791fdcee1f64638f0fc9abd6d2c7a1aa75fd3d2b80033170a02d025099dc",
|
||||||
|
"sourceBytes": 19947952,
|
||||||
|
"directMediaDurationSeconds": 1200.000998,
|
||||||
|
"sourceVerification": {
|
||||||
|
"status": "verified",
|
||||||
|
"dateUtc": "2026-10-14",
|
||||||
|
"method": "SHA-256, byte count, ffprobe format.duration, full FFmpeg decode",
|
||||||
|
"evidence": ".agent/evidence-v0.2.3/source-integrity.json"
|
||||||
|
},
|
||||||
|
"selectedSegmentStartSeconds": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"environmentId": "rain",
|
||||||
|
"displayName": "비 오는 거리",
|
||||||
|
"pageUrl": "https://commons.wikimedia.org/wiki/File:Urban_Street_on_a_Rainy_Afternoon.flac",
|
||||||
|
"directUrl": "https://upload.wikimedia.org/wikipedia/commons/8/8c/Urban_Street_on_a_Rainy_Afternoon.flac",
|
||||||
|
"creator": "Extemporalist",
|
||||||
|
"license": "CC0 1.0 Universal",
|
||||||
|
"licenseUrl": "https://creativecommons.org/publicdomain/zero/1.0/",
|
||||||
|
"attribution": "Suggested: Urban Street on a Rainy Afternoon, by Extemporalist, via Wikimedia Commons, CC0 1.0.",
|
||||||
|
"expectedSourceSha256": "ef0511593b1bb0ba47d5c5dafd83eb07ba854b5a65fd5d41b8c76a1b3ff2c22a",
|
||||||
|
"sourceBytes": 91187572,
|
||||||
|
"directMediaDurationSeconds": 1800.0,
|
||||||
|
"sourceVerification": {
|
||||||
|
"status": "verified",
|
||||||
|
"dateUtc": "2026-10-14",
|
||||||
|
"method": "SHA-256, byte count, ffprobe format.duration, full FFmpeg decode",
|
||||||
|
"evidence": ".agent/evidence-v0.2.3/source-integrity.json"
|
||||||
|
},
|
||||||
|
"selectedSegmentStartSeconds": 180
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"releaseRisks": [
|
||||||
|
"Audition chosen excerpts to avoid music and unnecessarily intelligible bystander speech.",
|
||||||
|
"The market derivative must stay CC BY-SA 4.0 with source, creator, change notice and license link.",
|
||||||
|
"The subway derivative needs CC BY 4.0 attribution and change notice.",
|
||||||
|
"Freesound direct URLs are preview MP3 files; preserve local source hashes and page/license evidence."
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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와 서버 배포는 실행하지 않았다.**
|
||||||
@@ -0,0 +1,394 @@
|
|||||||
|
# Find-Word v0.2.3 구현·검증 결과
|
||||||
|
|
||||||
|
작성일: 2026-10-14 UTC. worktree `/home/hermes/worktrees/find-word-v0.2.3`, branch `feat/v0.2.3`.
|
||||||
|
기준 HEAD `c92660b514f7af8eb556d3fa5c0fc80e4bdd4cf5`. 지정된 TASK/ACCEPTANCE/AMBIENCE-SOURCES를 먼저 읽고 기존 코드·테스트·문서를 확인했다.
|
||||||
|
|
||||||
|
**Git commit/push/merge/tag, 외부 배포, secrets 사용은 하지 않았다.** 로컬 production preview만 사용했다.
|
||||||
|
정확한 credit **Designed by OZ at Heat-T Medical Inc.**와 private/UNLICENSED 프로젝트 권리를 보존했다.
|
||||||
|
제3자 현장음은 각각의 라이선스를 유지한다.
|
||||||
|
|
||||||
|
**현재 screening 상태:** mall=36, market=24, cafe=0의 최종 WAV는 각각 segment 0개,
|
||||||
|
`duration_after_vad=0.0`, `requiredEmptyPassed=true`다. 사람의 청취 인수와 법적/privacy clearance는 false다.
|
||||||
|
전체 unit 125개·Python 36개·sandboxed Chrome 30개 및 lint/build가 통과했고 audit 취약점은 0개다.
|
||||||
|
실행 원문은 맨 아래 **최종 privacy screening 재시도** 절에 있다.
|
||||||
|
앞선 구현/독립 리뷰 기록은 당시 결과다. 이전 실패 screening은 별도 읽기 전용 경로에 원문 보존했다.
|
||||||
|
|
||||||
|
## 최초 구현 내용 (아래 리뷰 수정 내역으로 보완)
|
||||||
|
|
||||||
|
- 정확히 세 개의 서로 다른 문제/단어를 한 단계에서 출제한다. 시작 단계 1~5 선택, mixed 선택/입력/선택,
|
||||||
|
진행률/안내/분모 3문항, 정상 완료→다음 단계의 새 3문항, 5단계 재도전과 홈 복귀를 구현했다.
|
||||||
|
- SNR을 −12~+12 dB, 1 dB 눈금으로 직접 설정한다. 범위 밖 값은 clamp, NaN/Infinity는 단계 기본값으로 복구한다.
|
||||||
|
변경은 현재 재청취·미응답 문항·이후 라운드에 적용한다. 재생 중 gain을 바꾸지 않는다.
|
||||||
|
다음 단계도 수동 값은 유지하고 홈 복귀 시 수동 override를 지운다. 시작 단계/모드/환경/전체 음량은 홈 설정으로 유지한다.
|
||||||
|
- ready/loading/playing/answer/feedback에서 `문제 풀이 종료`가 가능하다. token 무효화→엔진 정지→결과 전환으로
|
||||||
|
지연 콜백을 차단한다. 응답 수·정답 수·실제 응답 분모를 표시하고 무응답을 오답으로 세지 않는다.
|
||||||
|
- 여덟 고유 실제 현장 녹음을 fetch/decode/loop한다. 절차적 잡음 합성 코드는 제거했다.
|
||||||
|
101개 음성 및 여덟 배경은 모두 same-origin `?v=0.2.3` 정적 요청이다. 런타임 외부 API/TTS/추적은 없다.
|
||||||
|
- 음성과 배경을 각각 RMS .03으로 정규화하고 상대 gain `10^(dB/20)`을 적용한다.
|
||||||
|
안내/목표/배경의 피크 합에 공통 gain을 적용해 최악 합계 peak ≤ .8을 유지한다.
|
||||||
|
master 음량은 그 뒤 공통 적용되므로 SNR을 보존한다. 배경은 목표 ended에서 함께 정리한다.
|
||||||
|
- HTTP/decode/준비 15초 timeout/재생 길이+5초 timeout/abort 후 한국어 안내와 재시도를 유지한다.
|
||||||
|
- CHANGELOG 생성, package/lock/HTML/UI/자산 버전/README/설계/배포/오디오/단어/권리 문서를 0.2.3에 맞췄다.
|
||||||
|
상세 한국어 설계 주석을 수정 코드의 모듈·함수·클래스·상태/매개변수·경합/수치 계산에 추가했다.
|
||||||
|
|
||||||
|
## RED → GREEN 원문
|
||||||
|
|
||||||
|
각 동작/회귀는 테스트를 먼저 작성·실행한 뒤 구현했다. 아래 RED의 종료 코드는 1, GREEN은 0이다.
|
||||||
|
`-t`로 좁힌 실행의 skipped는 필터 제외이며 최종 전체 실행은 skip 0이다. 실패 원문을 성공 로그로 대체하지 않았다.
|
||||||
|
|
||||||
|
| 계약/회귀 | RED → GREEN | 원문 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 세 문항/같은 시작 단계/혼합/점수 | 기존 10문항·자동 단계에서 3 실패 → 9 통과 | [01 RED](evidence-v0.2.3/01-round-RED.log), [01 GREEN](evidence-v0.2.3/01-round-GREEN.log) |
|
||||||
|
| SNR 정규화/미응답 전파/전 단계 종료/지연 이벤트 | 누락 reducer action 등 7 실패 → 15 통과 | [02 RED](evidence-v0.2.3/02-snr-exit-RED.log), [02 GREEN](evidence-v0.2.3/02-snr-exit-GREEN.log) |
|
||||||
|
| 시작 단계/수동 SNR/다음 라운드/5단계 경계/중도 결과/UI 초기화 | 10 실패 → 18 통과 | [03 RED](evidence-v0.2.3/03-screen-RED.log), [03 GREEN](evidence-v0.2.3/03-screen-GREEN.log) |
|
||||||
|
| 고유 녹음 URL/절차적 매개변수 제거/peak/SNR 수학 | 2 실패 → 콘텐츠 포함 19 통과 | [04 RED](evidence-v0.2.3/04-recorded-mix-RED.log), [04 GREEN](evidence-v0.2.3/04-recorded-mix-GREEN.log) |
|
||||||
|
| 실제 배경 fetch/decode/loop/abort/timeout/재시도 | 전환 중 남은 합성 호출 및 누락 녹음 경로로 9 실패 → 11 통과 | [05 RED](evidence-v0.2.3/05-playback-RED.log), [05 GREEN](evidence-v0.2.3/05-playback-GREEN.log) |
|
||||||
|
| Node 직접 import 회귀 | ERR_MODULE_NOT_FOUND → 101문장 import 통과 | [06 RED](evidence-v0.2.3/06-node-import-RED.log), [06 GREEN](evidence-v0.2.3/06-node-import-GREEN.log) |
|
||||||
|
| 8개 배포 PCM/해시/출처/고지/루프 경계 | manifest ENOENT → 전수 통과 | [07 RED](evidence-v0.2.3/07-assets-RED.log), [07 GREEN](evidence-v0.2.3/07-assets-GREEN.log) |
|
||||||
|
| 실제 FFmpeg 변환/재현/무음 거부/길이 제한 | 변환 모듈 없음 → Python 2 통과 | [변환 RED](evidence-v0.2.3/07-converter-RED.log), [변환 GREEN](evidence-v0.2.3/07-converter-GREEN.log) |
|
||||||
|
| 재생 중 SNR 변경의 실제 청취 이력 | −10을 들었다고 잘못 기록 → 34 통과 | [08 RED](evidence-v0.2.3/08-heard-snr-RED.log), [08 GREEN](evidence-v0.2.3/08-heard-snr-GREEN.log) |
|
||||||
|
| 버전/문서/변경 이력/기존 voice metadata | 이전 버전·누락 CHANGELOG → 50 통과 | [09 RED](evidence-v0.2.3/09-version-docs-RED.log), [09 GREEN](evidence-v0.2.3/09-version-docs-GREEN.log) |
|
||||||
|
| 3문항의 환경 순환 회귀 | 3개 환경만 도달 → 8개 도달, 35 통과 | [10 RED](evidence-v0.2.3/10-environment-rotation-RED.log), [10 GREEN](evidence-v0.2.3/10-environment-rotation-GREEN.log) |
|
||||||
|
| dist 현장음/manifest/notice 변조·누락·원본 혼입/고지 링크 | 5 실패 → 26 통과 | [11 RED](evidence-v0.2.3/11-bundle-notice-RED.log), [11 GREEN](evidence-v0.2.3/11-bundle-notice-GREEN.log) |
|
||||||
|
| 누락 WAV의 SPA fallback | desktop/mobile 200 HTML → 양쪽 404, 4 통과 | [13 RED](evidence-v0.2.3/13-static-404-RED.log), [13 GREEN](evidence-v0.2.3/13-static-404-GREEN.log) |
|
||||||
|
| 결과 화면의 잘못된 도움말 anchor | 없는 #howto 링크 노출 → 제거 | [15 RED](evidence-v0.2.3/15-results-anchor-RED.log), [15 GREEN](evidence-v0.2.3/15-results-anchor-GREEN.log) |
|
||||||
|
| 새 설정의 터치 크기/카드 경계 | 양쪽 23px 높이 → 44px 이상, 2 통과 | [16 RED](evidence-v0.2.3/16-controls-layout-RED.log), [16 GREEN](evidence-v0.2.3/16-controls-layout-GREEN.log) |
|
||||||
|
| 3문항의 보너스 안내 | 당시 40점 → 20점 안내; 리뷰에서 문항별 20점/합계 30점으로 재정정 | [17 RED](evidence-v0.2.3/17-bonus-copy-RED.log), [17 GREEN](evidence-v0.2.3/17-bonus-copy-GREEN.log) |
|
||||||
|
| 모바일 select 선택값 잘림 | 360px에서 글자 폭 초과 → 중복 SNR을 아래 제어에 모음 | [21 RED](evidence-v0.2.3/21-select-label-RED.log), [21 GREEN](evidence-v0.2.3/21-select-label-GREEN.log) |
|
||||||
|
| Chrome favicon 기본 404 | 내장 icon 없음/실제 콘솔 오류 → 내장 SVG | [19 RED](evidence-v0.2.3/19-favicon-RED.log), [19 GREEN](evidence-v0.2.3/19-favicon-GREEN.log) |
|
||||||
|
|
||||||
|
추가 진단 기록도 보존했다. `01-round-sampling-regression.log`의 96/100은 세 문항으로 줄인 뒤
|
||||||
|
기존 200 seed 표본이 작아진 테스트 회귀여서 1000 seed로 전체 100조합 도달성을 검사했다.
|
||||||
|
`03-screen-duplicate-description-RED.log`는 같은 SNR 설명을 중복 배치한 회귀를 잡았다.
|
||||||
|
`05-playback-fixture-regression.log` 뒤 mock AudioBuffer의 copyToChannel을 실제 복사처럼 보완했고
|
||||||
|
부동소수점 0.12000000000000001 비교를 근사 비교로 바꿨다. 실제 재생은 별도의 Chrome으로 검증한다.
|
||||||
|
`12-lint-initial.log`의 축소된 union 비교/fixture 타입 오류도 수정했다.
|
||||||
|
|
||||||
|
## 현장음 원본과 변환
|
||||||
|
|
||||||
|
지정된 원본 8개를 모두 사용했다. **대체 원본은 0개**다. 여섯 기존 원본을 재사용했고 café는
|
||||||
|
HTTP 429의 **Retry-After 600초** backoff 뒤 지정 직접 URL로 다운로드했다. rain도 지정 URL에서 받았다.
|
||||||
|
[다운로드 기록](evidence-v0.2.3/source-downloads.log), [rain 기록](evidence-v0.2.3/rain-download.log).
|
||||||
|
|
||||||
|
[원본 전수 검사](evidence-v0.2.3/source-integrity.json)는 전체 원본 SHA-256/bytes/ffprobe 정보와
|
||||||
|
FFmpeg **전체 디코드 8/8 성공, stderr 0**을 기록한다. café 19,947,952 bytes, rain 91,187,572 bytes는
|
||||||
|
Commons primary 메타데이터의 크기와 일치한다. [Commons API 근거](evidence-v0.2.3/commons-license-audit.json),
|
||||||
|
[primary 페이지/권리 재확인](evidence-v0.2.3/primary-page-verification.json).
|
||||||
|
|
||||||
|
`python3 scripts/ambience_audio.py`로 원본의 명시적 중간 구간을 선택해 전부 **12초 / 24,000Hz / mono / PCM16**으로 만들었다.
|
||||||
|
양끝 **50ms 선형 fade**, RMS 목표 **.08**, 최대 증폭 **4배**, peak ceiling **.85** 중 안전한 선형 gain을 적용했다.
|
||||||
|
저레벨 rain과 순간 peak가 큰 market은 제한 때문에 RMS 목표보다 낮다. 엔진은 재생 시 각각 다시 RMS 정규화한다.
|
||||||
|
양끝 PCM은 0, non-silent 8/8, 고유 출력 해시 8/8, 각 576,044 bytes, 합계 **4,608,352 bytes**다.
|
||||||
|
대형 OGG/MP3/FLAC 원본은 `/tmp/findword-ambience-sources`에만 있으며 Git/public/dist에 번들하지 않았다.
|
||||||
|
|
||||||
|
| 배포 자산 (`public/ambience/`) | 원본 구간 | RMS | peak | 출력 SHA-256 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| street.wav | 35–47s | 0.07999756 | 0.39675903 | `a8bffa201b174618955bc51b860167169125304811aabe2086b0bb35b06c3ae1` |
|
||||||
|
| mall.wav | 20–32s | 0.07999757 | 0.55468750 | `6e9171f549cacadfaeedd57a41c8e2a76b0e789f5c9a97af029a8d3558c9f145` |
|
||||||
|
| theater.wav | 45–57s | 0.07999757 | 0.49508667 | `2d6a444fb7874cdf6b2d8a741a69175299b112eb66834912c025437d8277d635` |
|
||||||
|
| department.wav | 90–102s | 0.07999758 | 0.47497559 | `aa43f3d1d3e7c2b1f8ace24ecbda45d0ea3a031db941c39506dc6c1665b8efa7` |
|
||||||
|
| market.wav | 30–42s | 0.04922208 | 0.84997559 | `4287e971a12767f70da714e0c1aff30125268f9c3faf07ebfbcc0d2904f4a312` |
|
||||||
|
| subway.wav | 65–77s | 0.07999755 | 0.42529297 | `9faf70b68617d267b367a0f3692ed90015458543ab4b0844f6c704e6a724728f` |
|
||||||
|
| cafe.wav | 120–132s | 0.07999759 | 0.39709473 | `8db06f3f09bbd8409573ba4874c7ccdd1e7e825c8a61989a4efe66206a66c2d2` |
|
||||||
|
| rain.wav | 180–192s | 0.01138463 | 0.10241699 | `f4315084e820f742b0709de5bb0d1abd3d5af1730620e08c2948b70347356dd9` |
|
||||||
|
|
||||||
|
[배포 manifest](../public/ambience/manifest.json)에 environment id/표시 이름, source page/direct URL, creator,
|
||||||
|
license/license URL, attribution, 원본/출력 SHA-256, bytes/duration/RMS/peak, 실제 FFmpeg 버전과 변환 설정을 기록했다.
|
||||||
|
[AMBIENCE_NOTICES](../public/ambience/AMBIENCE_NOTICES.md)를 dist에 포함하고 UI에서 접근할 수 있다.
|
||||||
|
시장 파생 WAV는 **CC BY-SA 4.0**, 지하철은 **CC BY 4.0**, 나머지는 CC0/PD이며 출처·변경 고지를 보존했다.
|
||||||
|
프로젝트의 UNLICENSED를 이 녹음에 적용하지 않는다. 런타임 React/ReactDOM/scheduler의 기존 MIT 전문도 그대로 배포한다.
|
||||||
|
|
||||||
|
## 보존과 구체적 회귀 수정
|
||||||
|
|
||||||
|
- **101개 neural WAV 바이트/원문/해시 변경 0**. voice manifest는 배포 version만 0.2.3으로 올리고
|
||||||
|
`generatedForVersion: 0.1.1`을 추가했으며 생성 시각·provider·voice·prosody·도구/실측값은 보존했다.
|
||||||
|
- 기존 10 mechanic/100문장, 정답·오답 규칙·점수 공식·재청취·객관식/주관식/mixed·IME 보호를 유지했다.
|
||||||
|
- **과거 .agent 추적 파일 180개 모두 Git blob hash 동일**. v0.1/v0.1.1 RESULT와 evidence 수정 0.
|
||||||
|
[보존 검사](evidence-v0.2.3/preservation.json).
|
||||||
|
- 짧아진 라운드 때문에 순환 환경이 street/mall/theater에만 갇히는 회귀를 seed 기반 환경 셔플로 수정했다.
|
||||||
|
- 환경 URL 모듈 추가로 Python 생성기의 Node 직접 import가 깨지는 회귀를 명시적 `.ts` 경로로 수정했다.
|
||||||
|
- `heardDb`를 PLAY 시점에 기록해 재생 중 조절값이 과거 청취 이력/결과를 덮어쓰지 않게 했다.
|
||||||
|
- 중복 SNR 설명, 결과 화면의 없는 도움말 anchor, 실제 라운드 보너스 상한 안내를 바로잡았다.
|
||||||
|
- Vite dev/preview의 누락 WAV HTML fallback을 차단하고 Nginx 인계에도 `/ambience/` 404 규칙을 추가했다.
|
||||||
|
- 모바일 최종 이미지에서 시작 단계 select의 긴 선택값 잘림을 찾아 글자 폭 검사로 재현하고, 중복 SNR 표기를 전용 제어로 모았다.
|
||||||
|
- 실제 Chrome의 기본 `/favicon.ico` 404 콘솔 오류를 내장 SVG로 제거했다.
|
||||||
|
|
||||||
|
## 리뷰 전 검증 기록 (리뷰 수정 후 결과는 문서 하단)
|
||||||
|
|
||||||
|
환경: Node **26.7.0**, npm **11.19.0**, Python **3.11.16**, FFmpeg **6.1.1-3ubuntu5**, system Chrome **146.0.7680.80**.
|
||||||
|
[환경](evidence-v0.2.3/environment.json). Chrome sandbox 활성화, `--no-sandbox` 0개를 실행 중 process argv로 확인했다.
|
||||||
|
[실행 sandbox 기록](evidence-v0.2.3/chrome-sandbox.json); 설정 계약 테스트도 통과했다.
|
||||||
|
|
||||||
|
| 검증 | 결과 | 원문 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `npm run lint` | PASS, ESLint + TypeScript strict, exit 0 | [22-lint](evidence-v0.2.3/22-lint.log) |
|
||||||
|
| `npm test` | **13 files / 94 passed**, skip 0, exit 0; Python runner 포함 | [22-full-test](evidence-v0.2.3/22-full-test.log) |
|
||||||
|
| `python3 -m unittest discover -s tests/python -v` | **20 passed**, exit 0 (기존 neural 18 + 새 변환 2) | [18-python](evidence-v0.2.3/18-python.log) |
|
||||||
|
| `npm run build` | PASS, 101 voice + 8 ambience + 두 notice 검증, exit 0 | [22-build](evidence-v0.2.3/22-build.log) |
|
||||||
|
| `npm audit --json` | **취약점 0** (info/low/moderate/high/critical 모두 0), exit 0 | [audit JSON](evidence-v0.2.3/14-npm-audit.json) |
|
||||||
|
| 최종 sandboxed system Chrome desktop/mobile | **26 passed / 0 failed / 0 skipped**, exit 0; 실제 재생·접근성·무외부 요청 검증 | [22-browser](evidence-v0.2.3/22-browser.log), [machine-readable 결과](evidence-v0.2.3/browser-results.json) |
|
||||||
|
| 원본/배포 녹음 및 101개 voice 보존 | PASS | [원본](evidence-v0.2.3/source-integrity.json), [보존](evidence-v0.2.3/preservation.json) |
|
||||||
|
| 비밀정보 형식 검사 | **0 findings**, 값 노출 없이 경로/개수만 기록 | [scan](evidence-v0.2.3/secret-scan.json) |
|
||||||
|
| `git diff --check` | PASS | [최종 worktree 점검](evidence-v0.2.3/final-review.log) |
|
||||||
|
|
||||||
|
브라우저는 1280×1000 desktop / 360×800 mobile에서 같은 production build를 사용한다.
|
||||||
|
실제 디코드한 109 WAV의 response hash/bytes/24kHz/mono/duration/RMS/peak를 전수 대조하고,
|
||||||
|
앱에서 여덟 환경을 실제 loop로 재생 후 정지했다. 혼합 모드 세 문항 완주/재청취/키보드,
|
||||||
|
4단계 시작→5단계 새 라운드, 수동 SNR 유지/재청취/홈 초기화, 재생 중 종료/응답 뒤 종료,
|
||||||
|
intro/target/ambience 404 재시도, 누락 WAV의 HTML Accept 404, notice 원문 제공을 검사한다.
|
||||||
|
정상 흐름의 console/page errors·failed requests·외부 요청·axe violations가 모두 0이어야 통과한다.
|
||||||
|
브라우저 native audio 메서드를 관찰할 때 원래 메서드를 실행하며 가짜 decode/ended를 주입하지 않는다.
|
||||||
|
|
||||||
|
최종 캡처 8개와 실제 검사 JSON을 새 evidence에 보존했다. 모바일 게임/시작과 desktop 시작/결과의
|
||||||
|
레이아웃을 이미지로 확인했고, 결과 분모/현재 SNR/종료 버튼/고지 링크가 잘리지 않는다.
|
||||||
|
|
||||||
|
| 화면 | Desktop | Mobile |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 시작 | [PNG](evidence-v0.2.3/browser/desktop-start.png) | [PNG](evidence-v0.2.3/browser/mobile-start.png) |
|
||||||
|
| 게임 | [PNG](evidence-v0.2.3/browser/desktop-game.png) | [PNG](evidence-v0.2.3/browser/mobile-game.png) |
|
||||||
|
| 정상 결과 | [PNG](evidence-v0.2.3/browser/desktop-normal-results.png) | [PNG](evidence-v0.2.3/browser/mobile-normal-results.png) |
|
||||||
|
| 중도 종료 | [PNG](evidence-v0.2.3/browser/desktop-early-exit.png) | [PNG](evidence-v0.2.3/browser/mobile-early-exit.png) |
|
||||||
|
|
||||||
|
실제 109 WAV 해시/디코드/레벨 및 오류 0 집계:
|
||||||
|
[desktop JSON](evidence-v0.2.3/browser/desktop-audio-integrity.json),
|
||||||
|
[mobile JSON](evidence-v0.2.3/browser/mobile-audio-integrity.json).
|
||||||
|
세 문항→다음 단계→중도 종료→홈·재청취의 실제 소스 시작/정지 및 네트워크 집계:
|
||||||
|
[desktop runtime](evidence-v0.2.3/browser/desktop-runtime-audit.json),
|
||||||
|
[mobile runtime](evidence-v0.2.3/browser/mobile-runtime-audit.json).
|
||||||
|
|
||||||
|
초기 browser suite 24/24 통과 후 console/requestfailed 검사를 강화해 missing favicon을 찾았다.
|
||||||
|
그 실패는 `18-browser.log`에 남기고, 최종 검증은 별도 로그로 구분했다. 오류를 숨기거나 예외 목록으로 제외하지 않았다.
|
||||||
|
404/잘못된 WAV 주입 테스트의 의도적 실패 응답은 정상 흐름의 오류 0 집계와 구분한다.
|
||||||
|
|
||||||
|
## 실제 검증의 한계와 인계
|
||||||
|
|
||||||
|
- Chrome은 실제 WAV를 디코드하고 실제 AudioContext/BufferSource를 실행했다. 헤드리스 자동 검증은
|
||||||
|
스피커/헤드폰의 물리 음압, 한국어 청감, 개인의 난이도나 임상 효과를 보증하지 않는다.
|
||||||
|
- 녹음 장면은 primary 출처 설명으로 확인했고 짧은 연속 구간의 포맷/신호/해시/루프를 검증했다.
|
||||||
|
**사람이 여덟 구간을 직접 청취하여 음악·불필요하게 명료한 우연 대화가 없는지 판단하는 인수는 수행하지 않았다.**
|
||||||
|
자동 검사를 인간 청취 인증으로 주장하지 않는다. [샘플과 provenance](../docs/AUDIO_PROVENANCE.md)를 Neo가 검토할 수 있다.
|
||||||
|
- mobile은 system Chrome 360×800 viewport/touch emulation이다. 실제 Android/iOS 기기 및 Safari 검증은 별도다.
|
||||||
|
- SNR은 전체 버퍼 RMS에 대한 디지털 상대값이다. 현장음의 시간 변화 때문에 순간/주파수별 SNR은 다르다.
|
||||||
|
- 로컬 `dist`만 검증했다. production HTTPS/MIME/cache/서버 설정은 배포 후 Neo의 독립 검증 대상이다.
|
||||||
|
- 사용자 지시대로 commit/push/merge/tag/deploy는 미실행이다. acceptance의 Neo 릴리스 항목은 완료로 표시하지 않았다.
|
||||||
|
[DEPLOYMENT](../docs/DEPLOYMENT.md)에 feature push→main FF→annotated tag→fresh clone→commit-addressed 원자 배포/rollback 절차를 인계했다.
|
||||||
|
|
||||||
|
|
||||||
|
## 독립 리뷰 수정 — 2026-10-14
|
||||||
|
|
||||||
|
사용자가 요약한 두 독립 리뷰와 본 결과 문서를 읽고 release-hardening을 수행했다.
|
||||||
|
기존 uncommitted v0.2.3 작업을 이어서 수정했으며 commit/push/merge/tag/deploy는 하지 않았다.
|
||||||
|
새 실패 테스트를 먼저 실행하고 생산 코드/검증기를 수정했다. 이전 evidence 로그는 수정하지 않았다.
|
||||||
|
신규 기록은 모두 [review-fixes/](evidence-v0.2.3/review-fixes/) 아래에 있다.
|
||||||
|
|
||||||
|
### 수정 내용과 동작
|
||||||
|
|
||||||
|
1. 진행 막대는 답변 수가 아닌 **현재 문항 1/3 → 2/3 → 3/3**이다. 첫 재생·답변 전·피드백과
|
||||||
|
다음 라운드에서도 일관된다. 접근성 이름/값, native progress 위치, 실제 PNG 채움 픽셀까지 검사한다.
|
||||||
|
2. 결과/README/설계/CHANGELOG의 점수 설명은 **정답마다 단계×100점 + 연속 정답 보너스**,
|
||||||
|
**문항별 최대 20점, 라운드 합계 0+10+20=30점**이다. 1단계 세 정답의 **330점**을 실제 UI 흐름으로 검증했다.
|
||||||
|
3. 응답이 없으면 정답률은 **— / 응답 없음**이며 0%나 0/0을 보여 주지 않는다. 응답 없는 단계는 **미진행**이다.
|
||||||
|
중도 종료 제목은 **문제 풀이를 중간에 종료했어요.**, 정상 결과는 **N단계 문제 풀이를 마쳤어요.**로 구분한다.
|
||||||
|
4. 실제 Chrome RED에서 `입력`, 결과의 `만나요`/`최대` 등 어절 분리를 검출했다.
|
||||||
|
모드 설명과 결과 영역에 keep-all을 적용하고 줄바꿈을 허용했다. 320px/360px에서 어절 내부 Range 줄 분리와
|
||||||
|
요소/문서 overflow를 검사하며 시작·정상 결과·중도 결과 캡처를 남겼다.
|
||||||
|
5. README 현재 증거 경로를 `.agent/evidence-v0.2.3/review-fixes/`로 바로잡고 일본어 reducer 테스트 제목을 한국어로 바꿨다.
|
||||||
|
6. build verifier는 앱 콘텐츠의 10 patterns×10 words+intro로 **정확한 101개 이름**을 독립 구성한다.
|
||||||
|
manifest 정확히 101개, 중복 없는 예상 inventory, dist/audio의 추가/누락 파일을 모두 검사한다.
|
||||||
|
양쪽 manifest와 디렉터리를 함께 비우기/축약/중복/이름 변경해도 실패하며 정상 사본은 통과한다.
|
||||||
|
7. 승인 계획과 배포 manifest의 `verifiedLocalSource` 및 모호한 `sourceDurationSeconds`를 제거했다.
|
||||||
|
`expectedSourceSha256`, `sourceBytes`, `sourceVerification`과 **directUrl 바이트의 ffprobe format.duration**인
|
||||||
|
`directMediaDurationSeconds`를 보존한다. Freesound preview MP3의 길이와 primary 페이지 표시 길이를 혼동하지 않는다.
|
||||||
|
파생 WAV의 `duration`/`conversion.durationSeconds`는 별도로 12초다. 기존 source-integrity 증거와 대조했다.
|
||||||
|
8. 생성기는 **첫 변환 전에 여덟 원본 전부**의 승인 해시/bytes를 확인한다. 불일치/누락/중복/잘못된 목록은 실패하고,
|
||||||
|
현재 파일 값으로 승인 계획을 덮어쓰지 않는다. 실제 원본 8개도 새 승인 필드로 재검증했다.
|
||||||
|
9. 현장음 notice를 **public/ambience/AMBIENCE_NOTICES.md**로 옮겼다. 같은 파일시스템의 staging에서
|
||||||
|
8 WAV·manifest·notice와 실측 PCM을 전수 검사한 다음 Linux **renameat2(RENAME_EXCHANGE)** 한 번으로 교체한다.
|
||||||
|
최초 생성은 rename 한 번이다. overlay를 없애 stale 파일을 제거하고 정상/dangling symlink 출력을 거부한다.
|
||||||
|
모든 변환 위치의 실패/KeyboardInterrupt, manifest/notice 쓰기 실패, staged 변조, 교환 실패/미지원,
|
||||||
|
commit 전 SIGTERM에서 이전 디렉터리를 보존한다. 실제 교환 도중 디렉터리 fd로 읽은 세 파일이
|
||||||
|
같은 세대인 것도 확인했다. UI 링크·build verifier·권리·배포·재현 문서를 함께 수정했다.
|
||||||
|
10. 모든 배포 notice 항목에 **creator, primary page URL, direct download URL, license URL,
|
||||||
|
outputLicense, 명시적 Changes**가 있어야 한다. 다른 항목에 공통 URL이 남아도 누락을 감추지 못한다.
|
||||||
|
8개 항목×6개 필드 제거와 public/dist 동시 metadata 변조를 build verifier에서 거부한다.
|
||||||
|
11. CHANGELOG와 본 문서에 실제 수정/검증을 반영했다. **109 WAV 재생성 0 / 바이트 변경 0**이다.
|
||||||
|
|
||||||
|
### 새 RED → GREEN 원문
|
||||||
|
|
||||||
|
| 계약 | RED | GREEN |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 진행률·330점·보너스·무응답·종료/완료 문구·README | [01 RED](evidence-v0.2.3/review-fixes/01-ui-RED.log) | [01 GREEN-02: 27 통과](evidence-v0.2.3/review-fixes/01-ui-GREEN-02.log) |
|
||||||
|
| 실제 desktop/mobile 진행률·320/360px 어절·overflow | [02 RED: 4 실패](evidence-v0.2.3/review-fixes/02-browser-RED.log) | [02 GREEN: 4 통과](evidence-v0.2.3/review-fixes/02-browser-GREEN.log) |
|
||||||
|
| manifest/폴더 동시 축약·추가/누락 | [03 RED](evidence-v0.2.3/review-fixes/03-voice-inventory-RED.log) | [03 GREEN](evidence-v0.2.3/review-fixes/03-voice-inventory-GREEN.log) |
|
||||||
|
| durable 승인 원본 메타데이터 | [04 RED](evidence-v0.2.3/review-fixes/04-source-plan-RED.log) | [04 GREEN](evidence-v0.2.3/review-fixes/04-source-plan-GREEN.log) |
|
||||||
|
| 첫 변환 전 전수 원본 검사 | [05 RED](evidence-v0.2.3/review-fixes/05-source-guard-RED.log) | [05 GREEN](evidence-v0.2.3/review-fixes/05-source-guard-GREEN.log) |
|
||||||
|
| staging·notice·symlink·검증·원자 교환·실패/중단 보존 | [06 RED](evidence-v0.2.3/review-fixes/06-atomic-RED.log) | [06 GREEN](evidence-v0.2.3/review-fixes/06-atomic-GREEN.log) |
|
||||||
|
| notice 동시 발행 경로/UI 링크/항목 내용 | [07 RED](evidence-v0.2.3/review-fixes/07-notice-path-RED.log) | [07 GREEN](evidence-v0.2.3/review-fixes/07-notice-path-GREEN.log) |
|
||||||
|
| 항목별 필수 notice 강제 | [08 RED](evidence-v0.2.3/review-fixes/08-notice-verifier-RED.log) | [08–09 GREEN: 27 통과](evidence-v0.2.3/review-fixes/08-09-build-GREEN.log) |
|
||||||
|
| manifest 사본 동시 출처/라이선스/변경 변조 | [09 RED](evidence-v0.2.3/review-fixes/09-build-plan-RED.log) | [08–09 GREEN](evidence-v0.2.3/review-fixes/08-09-build-GREEN.log) |
|
||||||
|
|
||||||
|
RED 로그는 exit 1, 표에 연결한 GREEN은 exit 0이다. 필터 실행의 skipped는 최종 전체 실행과 구분한다.
|
||||||
|
`01-ui-GREEN.log`는 이름과 달리 **exit 1**인 중간 실행이다. 새 계약은 통과했지만 기존 통합 테스트의
|
||||||
|
이전 제목 regex가 남아 실패했고, 그것을 고친 `01-ui-GREEN-02.log`가 실제 GREEN이다. 실패 로그도 보존했다.
|
||||||
|
|
||||||
|
초기 RED/GREEN browser PNG를 사후 픽셀 분석한 [RED](evidence-v0.2.3/review-fixes/02-progress-pixels-RED.log) /
|
||||||
|
[GREEN](evidence-v0.2.3/review-fixes/02-progress-pixels-GREEN.log)도 보존했다. desktop 1096px 막대는
|
||||||
|
365→731→1096px, mobile 320px 막대는 107→213→320px 채워졌다. 같은 픽셀 검사를 최종 브라우저 테스트에도 넣었다.
|
||||||
|
추가 동시 읽기/미지원 교환 검증은 [10-atomic-additional](evidence-v0.2.3/review-fixes/10-atomic-additional.log)에 있다.
|
||||||
|
|
||||||
|
### 리뷰 수정 후 전체 검증
|
||||||
|
|
||||||
|
| 실행 | 실제 결과 | 원문 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| npm run lint | PASS, exit 0 | [lint](evidence-v0.2.3/review-fixes/11-lint.log) |
|
||||||
|
| npm test | 13 files / **118 passed**, skip 0, exit 0 | [unit](evidence-v0.2.3/review-fixes/11-unit.log) |
|
||||||
|
| python3 -m unittest discover -s tests/python -v | **32 passed** (neural 18 + ambience 14), exit 0 | [Python](evidence-v0.2.3/review-fixes/11-python.log) |
|
||||||
|
| npm run build | PASS, 101 voice + 8 ambience + runtime/ambience notices, exit 0 | [build](evidence-v0.2.3/review-fixes/11-build.log) |
|
||||||
|
| npm audit --json | **취약점 0**, exit 0 | [audit](evidence-v0.2.3/review-fixes/npm-audit.json) |
|
||||||
|
| sandboxed system Chrome desktop/mobile | **30 passed / 0 failed / 0 skipped / 0 flaky**, 4.0분, exit 0 | [browser log](evidence-v0.2.3/review-fixes/12-browser.log), [JSON](evidence-v0.2.3/review-fixes/browser-results.json) |
|
||||||
|
|
||||||
|
[보존 검사](evidence-v0.2.3/review-fixes/preservation.json): 리뷰 시작 시점의 WAV 109개와 이전 `.agent` 파일
|
||||||
|
268개 모두 해시 동일하다. Git 추적된 v0.1/v0.1.1 `.agent` 파일 180개도 HEAD와 동일하다.
|
||||||
|
[원본 재확인](evidence-v0.2.3/review-fixes/source-reverification.json): 승인 원본 8개와 배포 bundle을 검증했고 변환은 호출하지 않았다.
|
||||||
|
|
||||||
|
Chrome **146.0.7680.80**, desktop 1280×1000/mobile 360×800에 추가 320px/360px copy 검사를 수행했다.
|
||||||
|
실행 중인 이 테스트의 Chrome 프로세스 20개에 `--no-sandbox`가 없음을 [실제 process 기록](evidence-v0.2.3/review-fixes/chrome-sandbox.json)으로 확인했다.
|
||||||
|
원래 AudioContext/BufferSource를 실행한 109 WAV 해시·decode 검사와 8개 실제 ambience loop, 오류 재시도,
|
||||||
|
키보드/axe/외부 요청/콘솔 검사에 새 진행률 픽셀·한국어 어절 검사를 더했다.
|
||||||
|
[desktop 오디오](evidence-v0.2.3/review-fixes/desktop-audio-integrity.json),
|
||||||
|
[mobile 오디오](evidence-v0.2.3/review-fixes/mobile-audio-integrity.json),
|
||||||
|
[desktop runtime](evidence-v0.2.3/review-fixes/desktop-runtime-audit.json),
|
||||||
|
[mobile runtime](evidence-v0.2.3/review-fixes/mobile-runtime-audit.json).
|
||||||
|
|
||||||
|
| 최종 화면 | Desktop | Mobile |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 시작 | [PNG](evidence-v0.2.3/review-fixes/screenshots/desktop-start.png) | [PNG](evidence-v0.2.3/review-fixes/screenshots/mobile-start.png) |
|
||||||
|
| 게임 | [PNG](evidence-v0.2.3/review-fixes/screenshots/desktop-game.png) | [PNG](evidence-v0.2.3/review-fixes/screenshots/mobile-game.png) |
|
||||||
|
| 330점 정상 결과 | [PNG](evidence-v0.2.3/review-fixes/screenshots/desktop-normal-results.png) | [PNG](evidence-v0.2.3/review-fixes/screenshots/mobile-normal-results.png) |
|
||||||
|
| 무응답 중도 종료 | [PNG](evidence-v0.2.3/review-fixes/screenshots/desktop-early-exit.png) | [PNG](evidence-v0.2.3/review-fixes/screenshots/mobile-early-exit.png) |
|
||||||
|
|
||||||
|
### 리뷰 후에도 남는 한계
|
||||||
|
|
||||||
|
**사람이 여덟 현장음 구간을 청취하여 음악/우연 대화와 적절성을 판단하는 인수는 수행하지 않았다.**
|
||||||
|
자동 PCM/Chrome 재생 검증을 인간 청취 승인으로 주장하지 않는다. mobile은 Chrome viewport/touch emulation이며
|
||||||
|
실제 Android/iOS/Safari, 물리적 음압 또는 임상 효과 검증은 아니다.
|
||||||
|
|
||||||
|
원자 commit 전 실패/중단은 이전 디렉터리를 보존하며 commit 뒤에는 완성된 새 트리가 공개된다.
|
||||||
|
강제 kill은 숨은 stage를 남길 수 있다. 전원 손실 내구성이나 여러 HTTP 요청에 걸친 snapshot 격리는 검증하지 않았다.
|
||||||
|
로컬 build/preview만 확인했으며 사용자 지시대로 Git commit/push/merge/tag 및 배포는 하지 않았다.
|
||||||
|
|
||||||
|
|
||||||
|
## 최종 privacy screening 재시도 — 2026-10-14
|
||||||
|
|
||||||
|
이전 market 60초/cafe 180초의 ASR-empty 실패를 새 구간으로 수정했다.
|
||||||
|
현재 **mall=36, market=24, cafe=0**, 최종 8 WAV의 segment 수는 모두 0이다.
|
||||||
|
세 필수 환경의 `duration_after_vad=0.0`, `requiredEmptyPassed=true`를 실제 inference로 확인했다.
|
||||||
|
**humanListeningAcceptance=false / legalPrivacyClearance=false**이며 ASR만으로 청취 인수를 주장하지 않는다.
|
||||||
|
|
||||||
|
### TDD·생성·이전 증거 보존
|
||||||
|
|
||||||
|
[01-release-RED](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/01-release-RED.log)는
|
||||||
|
구현 전 정확한 새 시작점, true gate, market/cafe 바이트 변경 조건에서 3개 실패했다.
|
||||||
|
[04-release-GREEN](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/04-release-GREEN.log)은
|
||||||
|
원자 재생성·실제 ASR 이후 같은 6개 테스트를 실행한 결과다.
|
||||||
|
테스트는 VAD/decoder 설정, manifest/WAV 해시, empty segment/text와 0.0 VAD duration,
|
||||||
|
청취/법적 인수 false, 이전 실패 상태·no-VAD 해시·모든 보존 파일 해시를 강제한다.
|
||||||
|
|
||||||
|
계획의 market/cafe 시작점만 24/0으로 바꾸고 원본 해시·bytes·직접 미디어 길이·권리 정보는 유지했다.
|
||||||
|
[02-regeneration](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/02-regeneration.log)과
|
||||||
|
[regeneration.json](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/regeneration.json)은
|
||||||
|
원본 전수 확인 후 기존 하드닝된 생성기로 전체 bundle을 staging/검증/원자 교환한 근거다.
|
||||||
|
생성기는 계획을 변경하지 않았고 notice와 manifest도 같은 구간으로 발행했다.
|
||||||
|
이번에는 **market/cafe 두 WAV만 변경**, 101 voice와 다섯 unaffected ambience 및 mall WAV는 바이트 동일하다.
|
||||||
|
|
||||||
|
이전 screening 파일 89개 전체를 읽기 전용
|
||||||
|
[prior-attempt-market60-cafe180](evidence-v0.2.3/privacy-screening/prior-attempt-market60-cafe180/)에 복사·해시 고정했다.
|
||||||
|
[이전 final-asr.json](evidence-v0.2.3/privacy-screening/prior-attempt-market60-cafe180/final-asr.json)은
|
||||||
|
`requiredEmptyPassed=false`, mall 0 / market 3 / cafe 1 segment 그대로다.
|
||||||
|
SHA-256은 `01c8a92fab9f8df7a5f778c5f7e478ce96bcedc33e11a1055bd29154a08b706b`이며 테스트에도 고정했다.
|
||||||
|
이전 source plan/manifest/notices/RESULT/docs의 사본과
|
||||||
|
[시작 시점 baseline](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/baseline.json)도 남겼다.
|
||||||
|
실패 로그를 지우거나 성공으로 고쳐 쓰지 않았다.
|
||||||
|
|
||||||
|
### 정확한 최종 ASR와 한계
|
||||||
|
|
||||||
|
[현재 final-asr.json](evidence-v0.2.3/privacy-screening/final-asr.json),
|
||||||
|
[03-final-asr.log](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/03-final-asr.log):
|
||||||
|
faster-whisper 1.2.1, tiny multilingual revision `d90ca5fe260221311c53c58e660288d3deb8d356`,
|
||||||
|
CPU int8/4 threads, beam_size=5, best_of=5, 기본 Silero VAD, condition_on_previous_text=true,
|
||||||
|
자동 언어 감지, random seed 0. 이전 실패 실행과 전체 decoder/VAD 인자가 같은지 대조했다.
|
||||||
|
모델/VAD·입력 WAV·manifest·실행 script 해시, 의존성·모든 기본 설정·원문 segment/info를 기록했다.
|
||||||
|
반환 segment 삭제나 threshold 튜닝 없이 각 현재 WAV를 검사했다.
|
||||||
|
|
||||||
|
[no-vad-asr.json](evidence-v0.2.3/privacy-screening/no-vad-asr.json)의 SHA-256은
|
||||||
|
`14b42ee0b80c194caa3c0de2644f647d6d7720c60c2208374778619f47c2e969` 그대로다.
|
||||||
|
그 결과는 이전 mall 36/market 60/cafe 180초에서 나온 환각 가능 text이며 새 market/cafe 검사가 아니다.
|
||||||
|
**no-VAD 결과는 지정된 VAD gate를 대체하거나 뒤집지 않는다.** 기존 scan/raw provenance도 바이트 보존했다.
|
||||||
|
빈 VAD 결과도 말소리·음악·개인 대화의 부재를 증명하지 않고 출력 text/language도 충실한 전사가 아니다.
|
||||||
|
독립적인 사람 청취 인증과 법적/privacy clearance는 수행하지 않았다. 제품 소유자 Oz는
|
||||||
|
2026-10-14 제공된 최종 WAV 8개 검수 묶음과 자동 검사 한계를 기준으로 **현재 자산 그대로
|
||||||
|
릴리스를 진행하도록 명시적으로 승인**했다. 이 제품 결정은 제3자의 법적/privacy clearance를
|
||||||
|
대신하지 않는다.
|
||||||
|
|
||||||
|
### 현재 자산 무결성
|
||||||
|
|
||||||
|
| WAV | 원본 구간 | RMS | peak | SHA-256 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| street.wav | 35–47s | 0.07999756 | 0.39675903 | `a8bffa201b174618955bc51b860167169125304811aabe2086b0bb35b06c3ae1` |
|
||||||
|
| mall.wav | 36–48s | 0.07999755 | 0.71917725 | `680a769940c08f0d12c6c954c08366598dd8b5745e276f39c82b10d1a88261a1` |
|
||||||
|
| theater.wav | 45–57s | 0.07999757 | 0.49508667 | `2d6a444fb7874cdf6b2d8a741a69175299b112eb66834912c025437d8277d635` |
|
||||||
|
| department.wav | 90–102s | 0.07999758 | 0.47497559 | `aa43f3d1d3e7c2b1f8ace24ecbda45d0ea3a031db941c39506dc6c1665b8efa7` |
|
||||||
|
| market.wav | 24–36s | 0.04309857 | 0.84997559 | `d6f73d86aea98b83e2995e61baaa7315a0ea7adeebc093769d76e1569b207658` |
|
||||||
|
| subway.wav | 65–77s | 0.07999755 | 0.42529297 | `9faf70b68617d267b367a0f3692ed90015458543ab4b0844f6c704e6a724728f` |
|
||||||
|
| cafe.wav | 0–12s | 0.07999754 | 0.40573120 | `6853c121104940041c268a2891eadae032c17aa22b4c3b3ddfbc025262434995` |
|
||||||
|
| rain.wav | 180–192s | 0.01138463 | 0.10241699 | `f4315084e820f742b0709de5bb0d1abd3d5af1730620e08c2948b70347356dd9` |
|
||||||
|
|
||||||
|
### 재시도 전체 검증
|
||||||
|
|
||||||
|
| 검사 | 실제 결과 | 근거 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| lint / typecheck | PASS, exit 0 | [05-lint](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/05-lint.log) |
|
||||||
|
| 전체 unit | 13 files / **125 passed, 0 failed, 0 skipped**, exit 0 | [05-unit](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/05-unit.log) |
|
||||||
|
| 전체 Python | **36 passed**, exit 0 | [05-python](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/05-python.log) |
|
||||||
|
| build | PASS, 101 voice + 8 ambience 및 notices, exit 0 | [05-build](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/05-build.log) |
|
||||||
|
| npm audit | **취약점 0**, exit 0 | [audit](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/npm-audit.json) |
|
||||||
|
| sandboxed Chrome desktop/mobile | **30 passed / 0 failed / 0 skipped / 0 flaky**, exit 0 | [06-browser](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/06-browser.log), [JSON](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/browser-results.json) |
|
||||||
|
|
||||||
|
현재 자동 검증은 모두 통과했다. [validation-summary](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/validation-summary.json)는 위 실행들의
|
||||||
|
실제 exit code·결과를 확인한 뒤 작성했으며 사람의 인수/법적 clearance를 포함한 전체 승인으로 해석하지 않는다.
|
||||||
|
현재 ASR gate 통과를 이전 실패의 통과로 바꾸어 기록하지 않았다.
|
||||||
|
|
||||||
|
Chrome 146.0.7680.80, desktop 1280×1000 / mobile 360×800 touch emulation의 전체 suite는
|
||||||
|
240.7초 걸렸다. 이 runner의 Chrome 자손 process 4개에서
|
||||||
|
`--no-sandbox`가 없음을 [실제 process 기록](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/chrome-sandbox.json)으로 확인했다.
|
||||||
|
설정은 `chromiumSandbox=true`이고 opt-out 환경변수는 제거했다.
|
||||||
|
양쪽에서 현재 **109 WAV response SHA-256/bytes·실제 decode·길이·채널·sample rate**를 전수 확인했다.
|
||||||
|
[desktop 오디오](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/desktop-audio-integrity.json), [mobile 오디오](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/mobile-audio-integrity.json),
|
||||||
|
[독립 실측 대조](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/browser-integrity-summary.json): hash/bytes 정확히 일치,
|
||||||
|
RMS/peak 차이는 브라우저 float scaling을 고려한 PCM16 한 step 이내다.
|
||||||
|
정상 요청에서 외부 요청·console/page 오류·failed request는 모두 0이며,
|
||||||
|
실제 여덟 ambience loop, 오류 재시도, UI·키보드·axe, 320/360px 어절·진행률 픽셀 검사도 통과했다.
|
||||||
|
[desktop runtime](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/desktop-runtime-audit.json), [mobile runtime](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/mobile-runtime-audit.json).
|
||||||
|
|
||||||
|
브라우저는 첫 전체 실행에서 통과했다. 이후 artifact 수집의
|
||||||
|
[08 실패](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/08-browser-integrity.log)는
|
||||||
|
runtime attachment를 별도 파일로 예상했으나 Playwright JSON 안의 base64 body였기 때문이다.
|
||||||
|
초기 수집 script와 실패 로그를 보존했고, body 원문을 추출한
|
||||||
|
[09 성공](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/09-browser-integrity.log)에서
|
||||||
|
양쪽 109개 WAV와 runtime audit를 대조했다. 테스트 결과를 수정하거나 재분류하지 않았다.
|
||||||
|
|
||||||
|
| 현재 화면 | Desktop | Mobile |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 시작 | [PNG](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/screenshots/desktop-start.png) | [PNG](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/screenshots/mobile-start.png) |
|
||||||
|
| 게임 | [PNG](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/screenshots/desktop-game.png) | [PNG](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/screenshots/mobile-game.png) |
|
||||||
|
| 정상 결과 | [PNG](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/screenshots/desktop-normal-results.png) | [PNG](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/screenshots/mobile-normal-results.png) |
|
||||||
|
| 중도 종료 | [PNG](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/screenshots/desktop-early-exit.png) | [PNG](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/screenshots/mobile-early-exit.png) |
|
||||||
|
|
||||||
|
[보존 검사](evidence-v0.2.3/privacy-screening/retry-market24-cafe0/preservation.json): 101 voice·다섯 unaffected ambience·mall 바이트 동일,
|
||||||
|
이전 `.agent` 파일 484개·읽기 전용 prior-attempt 사본 89개·HEAD 추적 역사 파일 180개 해시 동일.
|
||||||
|
갱신 허용된 plan/RESULT/current ASR/current summary 4개는 이전 상태를 별도 보존했다.
|
||||||
|
원본 provenance는 지정 market/cafe 시작점 외에 변경이 없고 dist는 현재 bundle과 바이트 동일하다.
|
||||||
|
|
||||||
|
**한계와 인계:** 지정된 자동 VAD acceptance를 충족했다. 사람의 청취 인수와 법적/privacy clearance는
|
||||||
|
여전히 수행하지 않았으며 empty ASR은 말소리/음악의 부재 증거가 아니다.
|
||||||
|
mobile은 Chrome viewport/touch emulation이다. Git commit/push/merge/tag/deploy는 하지 않았다.
|
||||||
@@ -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 위험을 기록한다.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Find-Word v0.2.3 구현 작업
|
||||||
|
|
||||||
|
## 기준
|
||||||
|
|
||||||
|
- canonical repository: `https://source.ibit.kr/OZ-Group/Find-Word`
|
||||||
|
- 기준 커밋: `c92660b514f7af8eb556d3fa5c0fc80e4bdd4cf5`
|
||||||
|
- 작업 브랜치: `feat/v0.2.3`
|
||||||
|
- 제품 버전: `0.2.3`
|
||||||
|
- 배포 대상: `https://findword.heart-m.com/`
|
||||||
|
- 정확한 credit: `Designed by OZ at Heat-T Medical Inc.`
|
||||||
|
- 프로젝트 라이선스: private / all rights reserved / `UNLICENSED`
|
||||||
|
|
||||||
|
## 사용자 요구사항의 실행 해석
|
||||||
|
|
||||||
|
1. 각 라운드는 정확히 3문항이다.
|
||||||
|
2. 한 라운드의 자동 난이도는 3문항 내내 동일하다. 정상 완료 결과 화면에서 다음 난이도 버튼을 누르면 바로 다음 단계의 새 3문항 라운드가 시작된다. 5단계에서 완료하면 같은 단계 재도전 또는 처음 화면으로 돌아간다.
|
||||||
|
3. 시작 화면에서 시작 난이도(1~5)를 선택한다.
|
||||||
|
4. 사용자가 배경 대비 목표 음성 비율을 직접 조정할 수 있도록 SNR dB 제어를 제공한다. 게임 중 변경은 현재 재생 전/재청취와 이후 라운드 문항에 적용하며 자동으로 문항마다 변하지 않는다. 범위와 step은 안전하고 명시적으로 제한한다.
|
||||||
|
5. 진행 중 `문제 풀이 종료`를 누르면 현재 오디오를 즉시 중단하고, 지금까지 답한 문항 수와 정답 수를 보여 주는 중도 종료 결과 화면을 표시한다. 사용자가 `처음 화면으로`를 눌러 초기 화면으로 돌아간다. 무응답 문항을 오답으로 세지 않는다.
|
||||||
|
6. 기존 procedural white-noise 환경음을 제거하고, 길거리·쇼핑몰·극장·백화점·시장·지하철·카페·비 오는 거리의 실제 현장 녹음 8개를 정적 자산으로 번들한다. 환경마다 서로 다른 녹음을 사용한다.
|
||||||
|
7. 현장음은 공개·수정·재배포가 허용된 라이선스만 사용한다. 원본 URL, 직접 다운로드 URL, 저작자, 라이선스, 변환, 원본/배포 해시와 attribution을 manifest와 문서에 기록한다. NC/ND/불명확한 자산은 금지한다.
|
||||||
|
8. 배경음은 24kHz mono PCM16 WAV로 통일하고, 재생 시 RMS를 정규화한다. 목표 음성과의 상대 SNR이 사용자의 dB 설정을 따른다. 짧은 자산은 click 없이 loop하고 목표 음성 종료 때 정리한다.
|
||||||
|
9. 앱 런타임은 same-origin 정적 자산만 요청하며 외부 네트워크, 분석, 추적, runtime TTS를 추가하지 않는다.
|
||||||
|
10. `CHANGELOG.md`를 버전 히스토리 파일로 생성하고 v0.2.3의 모든 변경, 오류 수정, 자산/라이선스, 테스트와 배포 관련 변경을 기록한다. 이전 v0.1.1/v0.1.0의 핵심 이력도 보존한다.
|
||||||
|
11. 버전 문자열을 package, lock, HTML title, UI, README, manifest/문서와 빌드에 일관되게 `0.2.3`으로 반영한다.
|
||||||
|
12. 직접 작성·수정한 소스 코드에는 모듈, 함수, 클래스, 핵심 변수·매개변수, 비자명한 로직의 목적과 이유를 설명하는 상세한 한국어 주석을 단다. 타입 선언·자명한 JSX 태그마다 형식적 주석을 반복하지 말고 설계 의도를 설명한다.
|
||||||
|
|
||||||
|
## 개발 방식
|
||||||
|
|
||||||
|
- strict TDD: 각 동작의 실패하는 테스트를 먼저 실행해 RED를 남긴 뒤 최소 구현으로 GREEN을 확인한다.
|
||||||
|
- 과거 `.agent/evidence-v0.1.1`과 `.agent/RESULT*.md`는 수정하지 않는다.
|
||||||
|
- 새 evidence는 `.agent/evidence-v0.2.3/`, 결과는 `.agent/RESULT-v0.2.3.md`에 기록한다.
|
||||||
|
- production 코드 변경 전 테스트를 작성한다.
|
||||||
|
- 기존 100개 목표 음성과 게임 콘텐츠, 개인정보 미수집, 접근성, 정확한 credit을 보존한다.
|
||||||
|
- Codex는 commit, push, merge, tag, production 배포를 하지 않는다. Neo가 독립 검증 후 실행한다.
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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 바이트
|
||||||
@@ -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%)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
> find-word@0.1.1 lint
|
||||||
|
> eslint . && tsc --noEmit
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
found 0 vulnerabilities
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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 전문 확인
|
||||||
@@ -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>
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 62 KiB |
@@ -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
|
||||||
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 59 KiB |
@@ -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))
|
||||||
@@ -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');
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 passed (1)
|
||||||
|
Tests 9 passed | 6 skipped (15)
|
||||||
|
Start at 07:57:16
|
||||||
|
Duration 914ms (environment 77%, setup 12%, transform 6%, tests 4%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/game.test.ts (9 tests | 3 failed) 41ms
|
||||||
|
❯ 출제와 정답 판정 (5)
|
||||||
|
× 세 문제를 한 단계로 출제하고 혼합 응답 방식과 고유 문제를 보장한다 8ms
|
||||||
|
❯ 게임 상태·점수·경합 방지 (3)
|
||||||
|
× 세 문제를 끝내면 정답률·연속 정답·단계별 결과를 집계한다 2ms
|
||||||
|
× 시작 단계 1~5를 명시하면 세 문항 모두 같은 level/db이고 범위 밖 단계도 안전하다 2ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 3 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > 출제와 정답 판정 > 세 문제를 한 단계로 출제하고 혼합 응답 방식과 고유 문제를 보장한다
|
||||||
|
AssertionError: expected [ …(10) ] to have a length of 3 but got 10
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
- 3
|
||||||
|
+ 10
|
||||||
|
|
||||||
|
❯ tests/game.test.ts:51:23
|
||||||
|
49| it("세 문제를 한 단계로 출제하고 혼합 응답 방식과 고유 문제를 보장한다", () => {
|
||||||
|
50| const questions = createQuestions(42, "mixed");
|
||||||
|
51| expect(questions).toHaveLength(3);
|
||||||
|
| ^
|
||||||
|
52| expect(new Set(questions.map((q) => q.pattern.id)).size).toBe(3);
|
||||||
|
53| expect(new Set(questions.map((q) => q.environment.id)).size).toBe(…
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/3]⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > 게임 상태·점수·경합 방지 > 세 문제를 끝내면 정답률·연속 정답·단계별 결과를 집계한다
|
||||||
|
AssertionError: expected 'ready' to be 'results' // Object.is equality
|
||||||
|
|
||||||
|
Expected: "results"
|
||||||
|
Received: "ready"
|
||||||
|
|
||||||
|
❯ tests/game.test.ts:153:25
|
||||||
|
151| state = gameReducer(state, { type: "NEXT" });
|
||||||
|
152| }
|
||||||
|
153| expect(state.phase).toBe("results");
|
||||||
|
| ^
|
||||||
|
154| expect(state.bestStreak).toBe(2);
|
||||||
|
155| expect(state.streak).toBe(0);
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/3]⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > 시작 단계 1~5를 명시하면 세 문항 모두 같은 level/db이고 범위 밖 단계도 안전하다
|
||||||
|
AssertionError: expected [ [ 1, 6 ], [ 1, 6 ], [ 2, 3 ], …(7) ] to deeply equal [ [ 1, 6 ], [ 1, 6 ], [ 1, 6 ] ]
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
@@ -6,9 +6,37 @@
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
6,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
- 1,
|
||||||
|
- 6,
|
||||||
|
+ 2,
|
||||||
|
+ 3,
|
||||||
|
+ ],
|
||||||
|
+ [
|
||||||
|
+ 2,
|
||||||
|
+ 3,
|
||||||
|
+ ],
|
||||||
|
+ [
|
||||||
|
+ 3,
|
||||||
|
+ 0,
|
||||||
|
+ ],
|
||||||
|
+ [
|
||||||
|
+ 3,
|
||||||
|
+ 0,
|
||||||
|
+ ],
|
||||||
|
+ [
|
||||||
|
+ 4,
|
||||||
|
+ -3,
|
||||||
|
+ ],
|
||||||
|
+ [
|
||||||
|
+ 4,
|
||||||
|
+ -3,
|
||||||
|
+ ],
|
||||||
|
+ [
|
||||||
|
+ 5,
|
||||||
|
+ -6,
|
||||||
|
+ ],
|
||||||
|
+ [
|
||||||
|
+ 5,
|
||||||
|
+ -6,
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
❯ tests/game.test.ts:175:49
|
||||||
|
173| for (const level of LEVELS) {
|
||||||
|
174| const questions = createQuestions(42, "mixed", "rotate", level.id);
|
||||||
|
175| expect(questions.map(q => [q.level, q.db])).toEqual(Array(3).fill(…
|
||||||
|
| ^
|
||||||
|
176| }
|
||||||
|
177| for (const [input, expected] of [[NaN, 1], [-4, 1], [99, 5], [2.7, 3…
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/3]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 3 failed | 6 passed (9)
|
||||||
|
Start at 07:56:19
|
||||||
|
Duration 1.22s (environment 82%, setup 9%, transform 4%, tests 4%, worker 1%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/game.test.ts (9 tests | 1 failed) 26ms
|
||||||
|
❯ 출제와 정답 판정 (5)
|
||||||
|
× 목표 WAV 100개 모두 같은 명시적 cache-busting 버전과 정답 mapping을 유지한다 13ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > 출제와 정답 판정 > 목표 WAV 100개 모두 같은 명시적 cache-busting 버전과 정답 mapping을 유지한다
|
||||||
|
AssertionError: expected 96 to be 100 // Object.is equality
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
- 100
|
||||||
|
+ 96
|
||||||
|
|
||||||
|
❯ tests/game.test.ts:21:28
|
||||||
|
19| .map((q) => [q.id, q]),
|
||||||
|
20| );
|
||||||
|
21| expect(questions.size).toBe(100);
|
||||||
|
| ^
|
||||||
|
22| const versions = new Set<string | null>();
|
||||||
|
23| for (const q of questions.values()) {
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 1 failed | 8 passed (9)
|
||||||
|
Start at 07:56:50
|
||||||
|
Duration 861ms (environment 76%, setup 13%, transform 6%, tests 4%, worker 1%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 passed (1)
|
||||||
|
Tests 15 passed (15)
|
||||||
|
Start at 07:57:18
|
||||||
|
Duration 879ms (environment 75%, setup 13%, transform 5%, tests 4%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/game.test.ts (15 tests | 7 failed) 30ms
|
||||||
|
❯ 출제와 정답 판정 (5)
|
||||||
|
× 목표 WAV 100개 모두 같은 명시적 cache-busting 버전과 정답 mapping을 유지한다 12ms
|
||||||
|
× SNR을 정수 -12~12 dB로 제한하고 현재/남은 문항에 일관되게 적용한다 1ms
|
||||||
|
× readyで中止しても無応答を加算せず終了結果を保つ 3ms
|
||||||
|
× loadingで中止しても無応答を加算せず終了結果を保つ 1ms
|
||||||
|
× playingで中止しても無応答を加算せず終了結果を保つ 1ms
|
||||||
|
× answerで中止しても無応答を加算せず終了結果を保つ 1ms
|
||||||
|
× feedbackで中止しても無応答を加算せず終了結果を保つ 1ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 7 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > 출제와 정답 판정 > 목표 WAV 100개 모두 같은 명시적 cache-busting 버전과 정답 mapping을 유지한다
|
||||||
|
AssertionError: expected 96 to be 100 // Object.is equality
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
- 100
|
||||||
|
+ 96
|
||||||
|
|
||||||
|
❯ tests/game.test.ts:21:28
|
||||||
|
19| .map((q) => [q.id, q]),
|
||||||
|
20| );
|
||||||
|
21| expect(questions.size).toBe(100);
|
||||||
|
| ^
|
||||||
|
22| const versions = new Set<string | null>();
|
||||||
|
23| for (const q of questions.values()) {
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/7]⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > SNR을 정수 -12~12 dB로 제한하고 현재/남은 문항에 일관되게 적용한다
|
||||||
|
TypeError: Cannot read properties of undefined (reading 'questions')
|
||||||
|
❯ tests/game.test.ts:186:21
|
||||||
|
184| for (const [input, expected] of [[-99, -12], [99, 12], [NaN, 3], [1.…
|
||||||
|
185| const adjusted = gameReducer(state, { type: "SNR", db: input! });
|
||||||
|
186| expect(adjusted.questions.map(q => q.db)).toEqual([expected, expec…
|
||||||
|
| ^
|
||||||
|
187| }
|
||||||
|
188| for (const type of ["PLAY", "STARTED", "ENDED"] as const) state = ga…
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/7]⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > readyで中止しても無応答を加算せず終了結果を保つ
|
||||||
|
FAIL tests/game.test.ts > loadingで中止しても無応答を加算せず終了結果を保つ
|
||||||
|
FAIL tests/game.test.ts > playingで中止しても無応答を加算せず終了結果を保つ
|
||||||
|
FAIL tests/game.test.ts > answerで中止しても無応答を加算せず終了結果を保つ
|
||||||
|
FAIL tests/game.test.ts > feedbackで中止しても無応答を加算せず終了結果を保つ
|
||||||
|
AssertionError: expected undefined to match object { phase: 'results', …(2) }
|
||||||
|
|
||||||
|
- Expected:
|
||||||
|
{
|
||||||
|
"answers": [],
|
||||||
|
"endedEarly": true,
|
||||||
|
"phase": "results",
|
||||||
|
}
|
||||||
|
|
||||||
|
+ Received:
|
||||||
|
undefined
|
||||||
|
|
||||||
|
❯ tests/game.test.ts:199:17
|
||||||
|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/7]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 7 failed | 8 passed (15)
|
||||||
|
Start at 07:56:51
|
||||||
|
Duration 918ms (environment 74%, setup 14%, transform 6%, tests 4%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 passed (1)
|
||||||
|
Tests 18 passed (18)
|
||||||
|
Start at 07:59:18
|
||||||
|
Duration 4.22s (tests 80%, environment 14%, setup 2%, transform 2%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,461 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/App.test.tsx (18 tests | 1 failed) 3085ms
|
||||||
|
❯ 시작부터 결과까지 사용자 흐름 (13)
|
||||||
|
× 다섯 난이도의 SNR과 음성·배경 크기 관계를 설명하고 결과에도 표시한다 112ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/App.test.tsx > 시작부터 결과까지 사용자 흐름 > 다섯 난이도의 SNR과 음성·배경 크기 관계를 설명하고 결과에도 표시한다
|
||||||
|
TestingLibraryElementError: Found multiple elements with the text: 음성이 배경보다 6 dB 커요.
|
||||||
|
|
||||||
|
Here are the matching elements:
|
||||||
|
|
||||||
|
Ignored nodes: comments, script, style
|
||||||
|
[36m<p[39m
|
||||||
|
[33mclass[39m=[32m"db-note"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m음성이 배경보다 6 dB 커요.[0m
|
||||||
|
[36m<br />[39m
|
||||||
|
[0m소리에 익숙해지기[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
|
||||||
|
Ignored nodes: comments, script, style
|
||||||
|
[36m<p[39m
|
||||||
|
[33mid[39m=[32m"snr-help"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m음성이 배경보다 6 dB 커요.[0m
|
||||||
|
[0m 범위 −12~+12 dB · 1 dB 간격. 양수는 음성이 더 크게, 0은 같게, 음수는 더 작게 들려요. 변경은 다음 재생·재청취부터 적용돼요.[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
|
||||||
|
(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).
|
||||||
|
|
||||||
|
Ignored nodes: comments, script, style
|
||||||
|
[36m<body>[39m
|
||||||
|
[36m<div>[39m
|
||||||
|
[36m<a[39m
|
||||||
|
[33mclass[39m=[32m"skip-link"[39m
|
||||||
|
[33mhref[39m=[32m"#main"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m본문으로 건너뛰기[0m
|
||||||
|
[36m</a>[39m
|
||||||
|
[36m<header[39m
|
||||||
|
[33mclass[39m=[32m"header wrap"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"brand"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[33mclass[39m=[32m"brand-mark"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<h1>[39m
|
||||||
|
[0m단어를 맞춰라[0m
|
||||||
|
[36m</h1>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"version"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mv0.1.1[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"header-actions"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<button[39m
|
||||||
|
[33mclass[39m=[32m"text-button"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m문제 풀이 종료[0m
|
||||||
|
[36m</button>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"little-dot"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[0m소리에 집중하는 시간[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</header>[39m
|
||||||
|
[36m<main[39m
|
||||||
|
[33mclass[39m=[32m"wrap"[39m
|
||||||
|
[33mid[39m=[32m"main"[39m
|
||||||
|
[33mtabindex[39m=[32m"-1"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<section[39m
|
||||||
|
[33maria-label[39m=[32m"단어 찾기 게임"[39m
|
||||||
|
[33mclass[39m=[32m"game-layout"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"game-top"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"eyebrow"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m나의 소리 탐험[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m문제 [0m
|
||||||
|
[36m<b>[39m
|
||||||
|
[0m01[0m
|
||||||
|
[36m</b>[39m
|
||||||
|
[0m / [0m
|
||||||
|
[0m3[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<progress[39m
|
||||||
|
[33maria-label[39m=[32m"전체 진행률"[39m
|
||||||
|
[33mmax[39m=[32m"3"[39m
|
||||||
|
[33mvalue[39m=[32m"0"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"game-columns"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<aside[39m
|
||||||
|
[33mclass[39m=[32m"environment-panel"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<p[39m
|
||||||
|
[33mclass[39m=[32m"eyebrow"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m지금 듣고 있는 공간[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m<h2>[39m
|
||||||
|
[0m길거리[0m
|
||||||
|
[36m</h2>[39m
|
||||||
|
[36m<p>[39m
|
||||||
|
[0m지나가는 차와 도시의 웅성임[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[33mclass[39m=[32m"mascot small"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"ear left"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"ear right"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"eye left"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"eye right"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"smile"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<b>[39m
|
||||||
|
[0mS[0m
|
||||||
|
[36m</b>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[33mclass[39m=[32m"sound-wave "[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 10px; animation-delay: 0s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 33.799955450859244px; animation-delay: 0.05s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 16.132986448643948px; animation-delay: 0.1s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 32.219552375865575px; animation-delay: 0.15000000000000002s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 21.858720427326595px; animation-delay: 0.2s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 29.163690702963766px; animation-delay: 0.25s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 26.796992502245015px; animation-delay: 0.30000000000000004s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 24.835290693688798px; animation-delay: 0.35000000000000003s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 30.619883556555898px; animation-delay: 0.4s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 35.39139668035928px; animation-delay: 0.45s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 71.52943948029164px; animation-delay: 0.5s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 19.53593765210872px; animation-delay: 0.55s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 73.98674560913082px; animation-delay: 0.6000000000000001s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 16.952742107140878px; animation-delay: 0.65s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 72.19510052760725px; animation-delay: 0.7000000000000001s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 32.979734657418774px; animation-delay: 0.75s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 66.27347594564635px; animation-delay: 0.8s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 47.480789758355044px; animation-delay: 0.8500000000000001s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 56.615089141222136px; animation-delay: 0.9s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 59.492984932238116px; animation-delay: 0.9500000000000001s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 43.861291911681526px; animation-delay: 1s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 68.21866699734562px; animation-delay: 1.05s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 28.858982496016484px; animation-delay: 1.1s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 73.07841912260051px; animation-delay: 1.1500000000000001s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 12.60436847039135px; animation-delay: 1.2000000000000002s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 73.74953619965402px; animation-delay: 1.25s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 23.8231850360459px; animation-delay: 1.3s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 32.57029511072814px; animation-delay: 1.35s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 20.99981090780238px; animation-delay: 1.4000000000000001s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 29.735764963203792px; animation-delay: 1.4500000000000002s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 26.085500220240995px; animation-delay: 1.5s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 25.59070868046883px; animation-delay: 1.55s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 30.10305417152866px; animation-delay: 1.6s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 20.410372983416416px; animation-delay: 1.6500000000000001s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 32.785692656480826px; animation-delay: 1.7000000000000002s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"level-tag"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m1[0m
|
||||||
|
[0m단계 · [0m
|
||||||
|
[0mSNR +6 dB[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<p[39m
|
||||||
|
[33mclass[39m=[32m"db-note"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m음성이 배경보다 6 dB 커요.[0m
|
||||||
|
[36m<br />[39m
|
||||||
|
[0m소리에 익숙해지기[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"snr-control"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<label[39m
|
||||||
|
[33mfor[39m=[32m"snr"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m목표 음성 SNR[0m
|
||||||
|
[36m</label>[39m
|
||||||
|
[36m<input[39m
|
||||||
|
[33maria-describedby[39m=[32m"snr-help"[39m
|
||||||
|
[33mid[39m=[32m"snr"[39m
|
||||||
|
[33mmax[39m=[32m"12"[39m
|
||||||
|
[33mmin[39m=[32m"-12"[39m
|
||||||
|
[33mstep[39m=[32m"1"[39m
|
||||||
|
[33mtype[39m=[32m"range"[39m
|
||||||
|
[33mvalue[39m=[32m"6"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<output[39m
|
||||||
|
[33mfor[39m=[32m"snr"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mSNR +6 dB[0m
|
||||||
|
[36m</output>[39m
|
||||||
|
[36m<p[39m
|
||||||
|
[33mid[39m=[32m"snr-help"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m음성이 배경보다 6 dB 커요.[0m
|
||||||
|
[0m 범위 −12~+12 dB · 1 dB 간격. 양수는 음성이 더 크게, 0은 같게, 음수는 더 작게 들려요. 변경은 다음 재생·재청취부터 적용돼요.[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"volume-row"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<label[39m
|
||||||
|
[33mfor[39m=[32m"volume"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m◖))[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[0m 전체 음량[0m
|
||||||
|
[36m</label>[39m
|
||||||
|
[36m<input[39m
|
||||||
|
[33mid[39m=[32m"volume"[39m
|
||||||
|
[33mmax[39m=[32m"100"[39m
|
||||||
|
[33mmin[39m=[32m"0"[39m
|
||||||
|
[33mtype[39m=[32m"range"[39m
|
||||||
|
[33mvalue[39m=[32m"35"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<output[39m
|
||||||
|
[33mfor[39m=[32m"volume"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m35[0m
|
||||||
|
[0m%[0m
|
||||||
|
[36m</output>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"mini-stats"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m점수 [0m
|
||||||
|
[36m<b>[39m
|
||||||
|
[0m0[0m
|
||||||
|
[36m</b>[39m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m연속 정답 [0m
|
||||||
|
[36m<b>[39m
|
||||||
|
[0m0[0m
|
||||||
|
[36m</b>[39m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</aside>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"question-panel panel"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"question-meta"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m바로잡은 말[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m객관식[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<h2[39m
|
||||||
|
[33mtabindex[39m=[32m"-1"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m정정해서 알려준 단어는 무엇인가요?[0m
|
||||||
|
[36m</h2>[39m
|
||||||
|
[36m<p[39m
|
||||||
|
[33mclass[39m=[32m"muted"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m가장 또렷하게 기억나는 단어를 골라 주세요.[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33maria-label[39m=[32m"답 선택"[39m
|
||||||
|
[33mclass[39m=[32m"answers"[39m
|
||||||
|
[33mrole[39m=[32m"group"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<button>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m1[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[0m시장[0m
|
||||||
|
[36m</button>[39m
|
||||||
|
[36m<button>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m2[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[0m지장[0m
|
||||||
|
[36m</button>[39m
|
||||||
|
[36m<button>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m3[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[0m사장[0m
|
||||||
|
[36m</button>[39m
|
||||||
|
[36m<button>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m4[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[0m신장[0m
|
||||||
|
[36m</button>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"play-controls"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<button[39m
|
||||||
|
[33mclass[39m=[32m"secondary"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m↻ 다시 듣기[0m
|
||||||
|
[36m</button>[39m
|
||||||
|
[36m<small>[39m
|
||||||
|
[0m다시 들어도 점수는 줄어들지 않아요.[0m
|
||||||
|
[36m</small>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</section>[39m
|
||||||
|
[36m</main>[39m
|
||||||
|
[36m<footer[39m
|
||||||
|
[33mclass[39m=[32m"footer wrap"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<p>[39m
|
||||||
|
[0mDesigned by OZ at Heat-T Medical Inc.[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m<p>[39m
|
||||||
|
[0m청각적 주의·식별 게임 · 의료적 진단이나 치료를 제공하지 않습니다.[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m개인정보 수집 없이, 오직 플레이만.[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</footer>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</body>[39m
|
||||||
|
❯ Object.getElementError node_modules/@testing-library/dom/dist/config.js:37:19
|
||||||
|
❯ getElementError node_modules/@testing-library/dom/dist/query-helpers.js:20:35
|
||||||
|
❯ getMultipleElementsFoundError node_modules/@testing-library/dom/dist/query-helpers.js:23:10
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:55:13
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:95:19
|
||||||
|
❯ tests/App.test.tsx:127:22
|
||||||
|
125| .toBeInTheDocument();
|
||||||
|
126| expect
|
||||||
|
127| .soft(screen.queryByText(description, { exact: false }))
|
||||||
|
| ^
|
||||||
|
128| .toBeInTheDocument();
|
||||||
|
129| await f.user.click(
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 1 failed | 17 passed (18)
|
||||||
|
Start at 07:59:02
|
||||||
|
Duration 4.01s (tests 79%, environment 14%, transform 2%, setup 2%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 2 passed (2)
|
||||||
|
Tests 19 passed (19)
|
||||||
|
Start at 08:00:13
|
||||||
|
Duration 1.06s (environment 76%, setup 12%, transform 8%, tests 2%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/dsp.test.ts (4 tests | 2 failed) 13ms
|
||||||
|
❯ 상대 dB와 결정론적 배경 합성 (4)
|
||||||
|
× 여덟 환경은 고유 same-origin WAV이며 절차적 합성 매개변수를 갖지 않는다 6ms
|
||||||
|
× 피크가 큰 녹음도 공통 감쇠로 합성 peak 0.8을 넘지 않고 SNR 비율을 보존한다 1ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/dsp.test.ts > 상대 dB와 결정론적 배경 합성 > 여덟 환경은 고유 same-origin WAV이며 절차적 합성 매개변수를 갖지 않는다
|
||||||
|
AssertionError: expected 1 to be 8 // Object.is equality
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
- 8
|
||||||
|
+ 1
|
||||||
|
|
||||||
|
❯ tests/dsp.test.ts:23:61
|
||||||
|
21| });
|
||||||
|
22| it("여덟 환경은 고유 same-origin WAV이며 절차적 합성 매개변수를 갖지 않는다", () => {
|
||||||
|
23| expect(new Set(ENVIRONMENTS.map(e => e.audioUrl)).size).toBe(8);
|
||||||
|
| ^
|
||||||
|
24| for (const environment of ENVIRONMENTS) {
|
||||||
|
25| const url = new URL(environment.audioUrl, "http://localhost");
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/2]⎯
|
||||||
|
|
||||||
|
FAIL tests/dsp.test.ts > 상대 dB와 결정론적 배경 합성 > 피크가 큰 녹음도 공통 감쇠로 합성 peak 0.8을 넘지 않고 SNR 비율을 보존한다
|
||||||
|
TypeError: mixingGains is not a function
|
||||||
|
❯ tests/dsp.test.ts:35:21
|
||||||
|
33| const background = normalizeRms(new Float32Array([0.2, -0.2]), 0.0…
|
||||||
|
34| for (const db of [-12, -6, 0, 6, 12]) {
|
||||||
|
35| const gains = mixingGains(voice, background, voice, db);
|
||||||
|
| ^
|
||||||
|
36| expect(20 * Math.log10(gains.voice / gains.background)).toBeClos…
|
||||||
|
37| expect(Math.max(...voice) * (gains.voice + gains.intro) + 0.03 *…
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/2]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 2 failed | 2 passed (4)
|
||||||
|
Start at 07:59:47
|
||||||
|
Duration 849ms (environment 78%, setup 14%, transform 5%, tests 2%, worker 1%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 passed (1)
|
||||||
|
Tests 11 passed (11)
|
||||||
|
Start at 08:01:57
|
||||||
|
Duration 1.05s (environment 60%, tests 21%, setup 10%, transform 6%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/audio.test.ts (11 tests | 9 failed) 139ms
|
||||||
|
❯ 오디오 재생 수명과 믹서 (8)
|
||||||
|
× intro와 목표 실제 fetch URL에 같은 명시적 cache-busting 버전을 붙인다 21ms
|
||||||
|
× intro 404 후 intro·목표를 동일한 versioned URL로 다시 요청한다 19ms
|
||||||
|
× target 404 후 intro·목표를 동일한 versioned URL로 다시 요청한다 20ms
|
||||||
|
× 생성 시 무음이며 gesture의 play에서만 장치를 연다 13ms
|
||||||
|
× 동시 시작을 거부하고 정지하면 모든 노드와 대기 Promise를 취소한다 14ms
|
||||||
|
× HTTP·디코드·장치 실패를 전달하고 다음 시도는 다시 로드한다 3ms
|
||||||
|
× 전체 음량은 두 신호의 비율을 보존하며 0부터 1 범위로 제한한다 9ms
|
||||||
|
× 선택한 녹음을 디코드·루프하고 목표 종료에서 모든 소스와 fetch를 정리한다 11ms
|
||||||
|
× 배경 404·디코드 실패는 한국어 복구 메시지이고 재시도로 성공한다 10ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 9 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > intro와 목표 실제 fetch URL에 같은 명시적 cache-busting 버전을 붙인다
|
||||||
|
TypeError: Cannot read properties of undefined (reading 'onended')
|
||||||
|
❯ tests/audio.test.ts:95:21
|
||||||
|
93| const done = f.engine.play(question, true, vi.fn());
|
||||||
|
94| await flush();
|
||||||
|
95| f.sources.at(-1)!.onended?.();
|
||||||
|
| ^
|
||||||
|
96| await done;
|
||||||
|
97| expect(f.fetcher.mock.calls.map(([url]) => url)).toEqual([
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/9]⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > intro 404 후 intro·목표를 동일한 versioned URL로 다시 요청한다
|
||||||
|
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > target 404 후 intro·목표를 동일한 versioned URL로 다시 요청한다
|
||||||
|
TypeError: Cannot read properties of undefined (reading 'onended')
|
||||||
|
❯ tests/audio.test.ts:129:23
|
||||||
|
127| const done = f.engine.play(question, true, vi.fn());
|
||||||
|
128| await flush();
|
||||||
|
129| f.sources.at(-1)!.onended?.();
|
||||||
|
| ^
|
||||||
|
130| await done;
|
||||||
|
131| expect(f.fetcher.mock.calls.map(([url]) => url)).toEqual([
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/9]⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > 생성 시 무음이며 gesture의 play에서만 장치를 연다
|
||||||
|
AssertionError: expected "vi.fn()" to be called once, but got 0 times
|
||||||
|
❯ tests/audio.test.ts:150:21
|
||||||
|
148| expect(f.context.resume).toHaveBeenCalledOnce();
|
||||||
|
149| await flush();
|
||||||
|
150| expect(started).toHaveBeenCalledOnce();
|
||||||
|
| ^
|
||||||
|
151| expect(f.sources).toHaveLength(3);
|
||||||
|
152| expect(
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/9]⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > 동시 시작을 거부하고 정지하면 모든 노드와 대기 Promise를 취소한다
|
||||||
|
AssertionError: expected TypeError: (0 , __vite_ssr_import_1__.syn… to match object { name: 'AbortError' }
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
- {
|
||||||
|
- "name": "AbortError",
|
||||||
|
+ TypeError {
|
||||||
|
+ "message": "(0 , __vite_ssr_import_1__.synthesizeBackground) is not a function",
|
||||||
|
}
|
||||||
|
|
||||||
|
❯ tests/audio.test.ts:182:35
|
||||||
|
180| const f = fixture();
|
||||||
|
181| const done = f.engine.play(question, false, vi.fn());
|
||||||
|
182| const cancelled = expect(done).rejects.toMatchObject({
|
||||||
|
| ^
|
||||||
|
183| name: "AbortError",
|
||||||
|
184| });
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/9]⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > HTTP·디코드·장치 실패를 전달하고 다음 시도는 다시 로드한다
|
||||||
|
AssertionError: expected [Function] to throw error including '해석' but got 'decode'
|
||||||
|
|
||||||
|
Expected: "해석"
|
||||||
|
Received: "decode"
|
||||||
|
|
||||||
|
❯ tests/audio.test.ts:226:58
|
||||||
|
224| );
|
||||||
|
225| f.context.decodeAudioData.mockRejectedValueOnce(new Error("decode"…
|
||||||
|
226| await expect(f.engine.play(question, false, vi.fn())).rejects.toTh…
|
||||||
|
| ^
|
||||||
|
227| "해석",
|
||||||
|
228| );
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/9]⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > 전체 음량은 두 신호의 비율을 보존하며 0부터 1 범위로 제한한다
|
||||||
|
TypeError: Cannot read properties of undefined (reading 'onended')
|
||||||
|
❯ tests/audio.test.ts:248:21
|
||||||
|
246| f.engine.setVolume(-1);
|
||||||
|
247| expect(f.gains[0]!.gain.setTargetAtTime).toHaveBeenCalledWith(0, 2…
|
||||||
|
248| f.sources.at(-1)!.onended?.();
|
||||||
|
| ^
|
||||||
|
249| await done;
|
||||||
|
250| });
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/9]⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 선택한 녹음을 디코드·루프하고 목표 종료에서 모든 소스와 fetch를 정리한다
|
||||||
|
AssertionError: expected "vi.fn()" to be called with arguments: [ Array(2) ]
|
||||||
|
|
||||||
|
Received:
|
||||||
|
|
||||||
|
1st vi.fn() call:
|
||||||
|
|
||||||
|
[
|
||||||
|
- "/ambience/street.wav?v=0.1.1",
|
||||||
|
- ObjectContaining {
|
||||||
|
- "signal": Any<AbortSignal>,
|
||||||
|
+ "/audio/correction-market.wav?v=0.1.1",
|
||||||
|
+ {
|
||||||
|
+ "signal": AbortSignal {
|
||||||
|
+ Symbol(kEvents): undefined,
|
||||||
|
+ Symbol(events.maxEventTargetListeners): 0,
|
||||||
|
+ Symbol(events.maxEventTargetListenersWarned): false,
|
||||||
|
+ Symbol(kHandlers): undefined,
|
||||||
|
+ Symbol(kAborted): true,
|
||||||
|
+ Symbol(kReason): AbortError {
|
||||||
|
+ "message": "This operation was aborted",
|
||||||
|
+ },
|
||||||
|
+ Symbol(kComposite): false,
|
||||||
|
+ },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Number of calls: 1
|
||||||
|
|
||||||
|
❯ tests/audio.test.ts:258:21
|
||||||
|
256| const done = f.engine.play(question, false, vi.fn());
|
||||||
|
257| await flush();
|
||||||
|
258| expect(f.fetcher).toHaveBeenCalledWith(question.environment.audioUrl…
|
||||||
|
| ^
|
||||||
|
259| expect(f.context.decodeAudioData).toHaveBeenCalledTimes(2);
|
||||||
|
260| expect(f.sources[0]!.loop).toBe(true);
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/9]⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 배경 404·디코드 실패는 한국어 복구 메시지이고 재시도로 성공한다
|
||||||
|
AssertionError: expected [Function] to throw error matching /배경.*다시/ but got '(0 , __vite_ssr_import_1__.synthesize…'
|
||||||
|
|
||||||
|
- Expected:
|
||||||
|
/배경.*다시/
|
||||||
|
|
||||||
|
+ Received:
|
||||||
|
"(0 , __vite_ssr_import_1__.synthesizeBackground) is not a function"
|
||||||
|
|
||||||
|
❯ tests/audio.test.ts:272:56
|
||||||
|
270| f.fetcher.mockImplementationOnce(async () => ({ ok: true, arrayBuffe…
|
||||||
|
271| f.fetcher.mockResolvedValueOnce({ ok: false } as Response);
|
||||||
|
272| await expect(f.engine.play(question, false, vi.fn())).rejects.toThro…
|
||||||
|
| ^
|
||||||
|
273| f.context.decodeAudioData.mockRejectedValueOnce(new Error("EncodingE…
|
||||||
|
274| await expect(f.engine.play(question, false, vi.fn())).rejects.toThro…
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/9]⎯
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
Vitest caught 6 unhandled errors during the test run.
|
||||||
|
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.
|
||||||
|
|
||||||
|
⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
|
||||||
|
TypeError: synthesizeBackground is not a function
|
||||||
|
❯ src/audio/engine.ts:131:15
|
||||||
|
129| background.copyToChannel(
|
||||||
|
130| normalizeRms(
|
||||||
|
131| synthesizeBackground(
|
||||||
|
| ^
|
||||||
|
132| question.environment,
|
||||||
|
133| context.sampleRate,
|
||||||
|
❯ process.processTicksAndRejections node:internal/process/task_queues:104:5
|
||||||
|
|
||||||
|
This error originated in "tests/audio.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
|
||||||
|
The last test to run before this error was "로드 시간초과는 fetch를 취소하고 늦은 디코드가 소스를 만들지 않는다". This means either:
|
||||||
|
- the error was thrown while Vitest was running this test, or
|
||||||
|
- the error was thrown after the test completed, and this was the most recent test at that point.
|
||||||
|
|
||||||
|
⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
|
||||||
|
TypeError: synthesizeBackground is not a function
|
||||||
|
❯ src/audio/engine.ts:131:15
|
||||||
|
129| background.copyToChannel(
|
||||||
|
130| normalizeRms(
|
||||||
|
131| synthesizeBackground(
|
||||||
|
| ^
|
||||||
|
132| question.environment,
|
||||||
|
133| context.sampleRate,
|
||||||
|
❯ process.processTicksAndRejections node:internal/process/task_queues:104:5
|
||||||
|
|
||||||
|
This error originated in "tests/audio.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
|
||||||
|
The last test to run before this error was "로드 시간초과는 fetch를 취소하고 늦은 디코드가 소스를 만들지 않는다". This means either:
|
||||||
|
- the error was thrown while Vitest was running this test, or
|
||||||
|
- the error was thrown after the test completed, and this was the most recent test at that point.
|
||||||
|
|
||||||
|
⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
|
||||||
|
TypeError: synthesizeBackground is not a function
|
||||||
|
❯ src/audio/engine.ts:131:15
|
||||||
|
129| background.copyToChannel(
|
||||||
|
130| normalizeRms(
|
||||||
|
131| synthesizeBackground(
|
||||||
|
| ^
|
||||||
|
132| question.environment,
|
||||||
|
133| context.sampleRate,
|
||||||
|
❯ process.processTicksAndRejections node:internal/process/task_queues:104:5
|
||||||
|
|
||||||
|
This error originated in "tests/audio.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
|
||||||
|
The last test to run before this error was "로드 시간초과는 fetch를 취소하고 늦은 디코드가 소스를 만들지 않는다". This means either:
|
||||||
|
- the error was thrown while Vitest was running this test, or
|
||||||
|
- the error was thrown after the test completed, and this was the most recent test at that point.
|
||||||
|
|
||||||
|
⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
|
||||||
|
TypeError: synthesizeBackground is not a function
|
||||||
|
❯ src/audio/engine.ts:131:15
|
||||||
|
129| background.copyToChannel(
|
||||||
|
130| normalizeRms(
|
||||||
|
131| synthesizeBackground(
|
||||||
|
| ^
|
||||||
|
132| question.environment,
|
||||||
|
133| context.sampleRate,
|
||||||
|
❯ process.processTicksAndRejections node:internal/process/task_queues:104:5
|
||||||
|
|
||||||
|
This error originated in "tests/audio.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
|
||||||
|
The last test to run before this error was "로드 시간초과는 fetch를 취소하고 늦은 디코드가 소스를 만들지 않는다". This means either:
|
||||||
|
- the error was thrown while Vitest was running this test, or
|
||||||
|
- the error was thrown after the test completed, and this was the most recent test at that point.
|
||||||
|
|
||||||
|
⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
|
||||||
|
TypeError: synthesizeBackground is not a function
|
||||||
|
❯ src/audio/engine.ts:131:15
|
||||||
|
129| background.copyToChannel(
|
||||||
|
130| normalizeRms(
|
||||||
|
131| synthesizeBackground(
|
||||||
|
| ^
|
||||||
|
132| question.environment,
|
||||||
|
133| context.sampleRate,
|
||||||
|
❯ process.processTicksAndRejections node:internal/process/task_queues:104:5
|
||||||
|
|
||||||
|
This error originated in "tests/audio.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
|
||||||
|
The last test to run before this error was "로드 시간초과는 fetch를 취소하고 늦은 디코드가 소스를 만들지 않는다". This means either:
|
||||||
|
- the error was thrown while Vitest was running this test, or
|
||||||
|
- the error was thrown after the test completed, and this was the most recent test at that point.
|
||||||
|
|
||||||
|
⎯⎯⎯⎯ Unhandled Rejection ⎯⎯⎯⎯⎯
|
||||||
|
TypeError: synthesizeBackground is not a function
|
||||||
|
❯ src/audio/engine.ts:131:15
|
||||||
|
129| background.copyToChannel(
|
||||||
|
130| normalizeRms(
|
||||||
|
131| synthesizeBackground(
|
||||||
|
| ^
|
||||||
|
132| question.environment,
|
||||||
|
133| context.sampleRate,
|
||||||
|
❯ process.processTicksAndRejections node:internal/process/task_queues:104:5
|
||||||
|
|
||||||
|
This error originated in "tests/audio.test.ts" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
|
||||||
|
The last test to run before this error was "로드 시간초과는 fetch를 취소하고 늦은 디코드가 소스를 만들지 않는다". This means either:
|
||||||
|
- the error was thrown while Vitest was running this test, or
|
||||||
|
- the error was thrown after the test completed, and this was the most recent test at that point.
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 9 failed | 2 passed (11)
|
||||||
|
Errors 6 errors
|
||||||
|
Start at 08:00:38
|
||||||
|
Duration 979ms (environment 65%, tests 16%, setup 11%, transform 6%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/audio.test.ts (11 tests | 1 failed) 207ms
|
||||||
|
❯ 오디오 재생 수명과 믹서 (8)
|
||||||
|
× 생성 시 무음이며 gesture의 play에서만 장치를 연다 30ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/audio.test.ts > 오디오 재생 수명과 믹서 > 생성 시 무음이며 gesture의 play에서만 장치를 연다
|
||||||
|
AssertionError: expected "vi.fn()" to be called with arguments: [ 1, Any<Number> ]
|
||||||
|
|
||||||
|
Received:
|
||||||
|
|
||||||
|
1st vi.fn() call:
|
||||||
|
|
||||||
|
[
|
||||||
|
- 1,
|
||||||
|
- Any<Number>,
|
||||||
|
+ 0.834156648304508,
|
||||||
|
+ 2.05,
|
||||||
|
]
|
||||||
|
|
||||||
|
2nd vi.fn() call:
|
||||||
|
|
||||||
|
[
|
||||||
|
- 1,
|
||||||
|
- Any<Number>,
|
||||||
|
+ 0,
|
||||||
|
+ 2.05,
|
||||||
|
]
|
||||||
|
|
||||||
|
3rd vi.fn() call:
|
||||||
|
|
||||||
|
[
|
||||||
|
- 1,
|
||||||
|
- Any<Number>,
|
||||||
|
+ 0.834156648304508,
|
||||||
|
+ 4.340000000000001,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Number of calls: 3
|
||||||
|
|
||||||
|
❯ tests/audio.test.ts:158:45
|
||||||
|
156| ).toEqual(["/audio/intro.wav", `/audio/${question.id}.wav`, new UR…
|
||||||
|
157| // master, 배경, 목표, 안내의 gain을 분리한다. 안내는 점차 소음에 묻힌다.
|
||||||
|
158| expect(f.gains[1]!.gain.setValueAtTime).toHaveBeenCalledWith(
|
||||||
|
| ^
|
||||||
|
159| 1,
|
||||||
|
160| expect.any(Number),
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 1 failed | 10 passed (11)
|
||||||
|
Start at 08:01:14
|
||||||
|
Duration 1.05s (environment 61%, tests 22%, setup 10%, transform 5%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 passed (1)
|
||||||
|
Tests 1 passed | 1 skipped (2)
|
||||||
|
Start at 08:01:59
|
||||||
|
Duration 305ms (setup 52%, tests 39%, transform 5%, worker 2%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/generator.test.ts (2 tests | 1 failed | 1 skipped) 87ms
|
||||||
|
× Node type stripping 경로에서 기존 101문장 원문을 읽을 수 있다 86ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/generator.test.ts > Node type stripping 경로에서 기존 101문장 원문을 읽을 수 있다
|
||||||
|
AssertionError: node:internal/modules/esm/resolve:272
|
||||||
|
throw new ERR_MODULE_NOT_FOUND(
|
||||||
|
^
|
||||||
|
|
||||||
|
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/hermes/worktrees/find-word-v0.2.3/src/audio/assets' imported from /home/hermes/worktrees/find-word-v0.2.3/src/content.ts
|
||||||
|
at finalizeResolution (node:internal/modules/esm/resolve:272:11)
|
||||||
|
at moduleResolve (node:internal/modules/esm/resolve:879:10)
|
||||||
|
at defaultResolve (node:internal/modules/esm/resolve:1006:11)
|
||||||
|
at #cachedDefaultResolve (node:internal/modules/esm/loader:708:20)
|
||||||
|
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:728:38)
|
||||||
|
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:766:56)
|
||||||
|
at #resolve (node:internal/modules/esm/loader:690:17)
|
||||||
|
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:610:35)
|
||||||
|
at ModuleJob.syncLink (node:internal/modules/esm/module_job:277:33)
|
||||||
|
at ModuleJob.link (node:internal/modules/esm/module_job:389:17) {
|
||||||
|
code: 'ERR_MODULE_NOT_FOUND',
|
||||||
|
url: 'file:///home/hermes/worktrees/find-word-v0.2.3/src/audio/assets'
|
||||||
|
}
|
||||||
|
|
||||||
|
Node.js v26.7.0
|
||||||
|
: expected 1 to be +0 // Object.is equality
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
- 0
|
||||||
|
+ 1
|
||||||
|
|
||||||
|
❯ tests/generator.test.ts:20:40
|
||||||
|
18| const result = spawnSync("node", ["--experimental-strip-types", "--i…
|
||||||
|
19| "import {INTRO,PATTERNS,WORDS} from './src/content.ts'; console.lo…
|
||||||
|
20| expect(result.status, result.stderr).toBe(0);
|
||||||
|
| ^
|
||||||
|
21| expect(result.stdout.trim()).toBe("101");
|
||||||
|
22| });
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 1 failed | 1 skipped (2)
|
||||||
|
Start at 08:01:37
|
||||||
|
Duration 340ms (setup 45%, tests 39%, transform 12%, worker 2%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"files": 8,
|
||||||
|
"bytes": 4608352
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 passed (1)
|
||||||
|
Tests 1 passed (1)
|
||||||
|
Start at 08:08:06
|
||||||
|
Duration 482ms (tests 66%, setup 27%, transform 3%, import 2%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/ambience.test.ts (1 test | 1 failed) 10ms
|
||||||
|
× 여덟 현장 녹음은 고유 PCM16 WAV·짧은 fade·완전한 provenance/notice를 가진다 8ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/ambience.test.ts > 여덟 현장 녹음은 고유 PCM16 WAV·짧은 fade·완전한 provenance/notice를 가진다
|
||||||
|
Error: ENOENT: no such file or directory, open 'public/ambience/manifest.json'
|
||||||
|
❯ tests/ambience.test.ts:9:31
|
||||||
|
7| // 생성기 자기 보고 대신 배포 바이트의 형식·파형·권리 추적 정보를 독립 측정한다.
|
||||||
|
8| it("여덟 현장 녹음은 고유 PCM16 WAV·짧은 fade·완전한 provenance/notice를 가진다", () => {
|
||||||
|
9| const manifest = JSON.parse(readFileSync("public/ambience/manifest.j…
|
||||||
|
| ^
|
||||||
|
10| expect(manifest.version).toBe("0.2.3");
|
||||||
|
11| expect(manifest.files.map((f: {environmentId: string}) => f.environm…
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 1 failed (1)
|
||||||
|
Start at 08:02:57
|
||||||
|
Duration 378ms (setup 63%, transform 25%, import 5%, tests 4%, worker 2%)
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
test_convert_format_fade_normalization_and_reproducibility (test_ambience_audio.AmbienceConversion.test_convert_format_fade_normalization_and_reproducibility)
|
||||||
|
스테레오 48kHz 입력을 실제로 내려 섞고 길이·양끝·안전 피크를 확인한다. ... ok
|
||||||
|
test_silence_fails_before_publishing (test_ambience_audio.AmbienceConversion.test_silence_fails_before_publishing)
|
||||||
|
무음을 정상 현장 녹음으로 포장하지 않는다. ... ok
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Ran 2 tests in 1.134s
|
||||||
|
|
||||||
|
OK
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
test_ambience_audio (unittest.loader._FailedTest.test_ambience_audio) ... ERROR
|
||||||
|
|
||||||
|
======================================================================
|
||||||
|
ERROR: test_ambience_audio (unittest.loader._FailedTest.test_ambience_audio)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
ImportError: Failed to import test module: test_ambience_audio
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/home/hermes/.local/share/uv/python/cpython-3.11.16-linux-x86_64-gnu/lib/python3.11/unittest/loader.py", line 419, in _find_test_path
|
||||||
|
module = self._get_module_from_name(name)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
File "/home/hermes/.local/share/uv/python/cpython-3.11.16-linux-x86_64-gnu/lib/python3.11/unittest/loader.py", line 362, in _get_module_from_name
|
||||||
|
__import__(name)
|
||||||
|
File "/home/hermes/worktrees/find-word-v0.2.3/tests/python/test_ambience_audio.py", line 11, in <module>
|
||||||
|
import ambience_audio as audio
|
||||||
|
ModuleNotFoundError: No module named 'ambience_audio'
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Ran 1 test in 0.000s
|
||||||
|
|
||||||
|
FAILED (errors=1)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 2 passed (2)
|
||||||
|
Tests 34 passed (34)
|
||||||
|
Start at 08:04:49
|
||||||
|
Duration 4.34s (tests 66%, environment 26%, setup 4%, transform 2%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/game.test.ts (16 tests | 1 failed) 39ms
|
||||||
|
× 재생 중 변경된 SNR은 재청취 전 답변의 청취 이력을 덮어쓰지 않는다 7ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > 재생 중 변경된 SNR은 재청취 전 답변의 청취 이력을 덮어쓰지 않는다
|
||||||
|
AssertionError: expected -10 to be 6 // Object.is equality
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
- 6
|
||||||
|
+ -10
|
||||||
|
|
||||||
|
❯ tests/game.test.ts:215:32
|
||||||
|
213| state = gameReducer(state, { type: "ENDED" });
|
||||||
|
214| state = gameReducer(state, { type: "ANSWER", input: state.questions[…
|
||||||
|
215| expect(state.answers[0]!.db).toBe(6);
|
||||||
|
| ^
|
||||||
|
216| expect(state.questions[1]!.db).toBe(-10);
|
||||||
|
217| });
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 1 failed | 15 passed (16)
|
||||||
|
Start at 08:04:23
|
||||||
|
Duration 904ms (environment 74%, setup 12%, transform 6%, tests 5%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 5 passed (5)
|
||||||
|
Tests 50 passed (50)
|
||||||
|
Start at 08:07:17
|
||||||
|
Duration 4.95s (tests 52%, environment 34%, setup 9%, transform 3%, import 1%)
|
||||||
|
|
||||||
|
Environment jsdom was created 5 times · 2.74s total, 34% of tracked time
|
||||||
|
create it once per worker with pool: 'vmThreads' (keeps per-file isolation) or isolate: false (shares it across files)
|
||||||
|
learn more: https://vitest.dev/guide/improving-performance#test-environments
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 2 passed (2)
|
||||||
|
Tests 35 passed (35)
|
||||||
|
Start at 08:07:59
|
||||||
|
Duration 4.38s (tests 66%, environment 26%, setup 4%, transform 2%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/game.test.ts (17 tests | 1 failed) 43ms
|
||||||
|
× 순환 환경은 여러 라운드에서 여덟 장소 모두를 선택하고 라운드 내에는 중복되지 않는다 8ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/game.test.ts > 순환 환경은 여러 라운드에서 여덟 장소 모두를 선택하고 라운드 내에는 중복되지 않는다
|
||||||
|
AssertionError: expected 3 to be 8 // Object.is equality
|
||||||
|
|
||||||
|
- Expected
|
||||||
|
+ Received
|
||||||
|
|
||||||
|
- 8
|
||||||
|
+ 3
|
||||||
|
|
||||||
|
❯ tests/game.test.ts:227:21
|
||||||
|
225| questions.forEach(q => seen.add(q.environment.id));
|
||||||
|
226| }
|
||||||
|
227| expect(seen.size).toBe(8);
|
||||||
|
| ^
|
||||||
|
228| });
|
||||||
|
229|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 1 failed (1)
|
||||||
|
Tests 1 failed | 16 passed (17)
|
||||||
|
Start at 08:07:35
|
||||||
|
Duration 902ms (environment 74%, setup 13%, transform 6%, tests 5%, import 1%, worker 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 2 passed (2)
|
||||||
|
Tests 26 passed (26)
|
||||||
|
Start at 08:08:44
|
||||||
|
Duration 4.72s (tests 85%, environment 9%, setup 3%, transform 2%, import 1%)
|
||||||
|
|
||||||
@@ -0,0 +1,596 @@
|
|||||||
|
|
||||||
|
RUN v5.0.4 /home/hermes/worktrees/find-word-v0.2.3
|
||||||
|
|
||||||
|
❯ tests/App.test.tsx (19 tests | 1 failed | 18 skipped) 485ms
|
||||||
|
× 환경음 저작자·라이선스 고지를 같은 출처 링크로 제공한다 483ms
|
||||||
|
❯ tests/build.test.ts (7 tests | 4 failed | 3 skipped) 1387ms
|
||||||
|
× 현장음 wav 손상은 빌드 실패로 처리한다 348ms
|
||||||
|
× 현장음 manifest 손상은 빌드 실패로 처리한다 342ms
|
||||||
|
× 현장음 notice 손상은 빌드 실패로 처리한다 371ms
|
||||||
|
× 현장음 extra 손상은 빌드 실패로 처리한다 324ms
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 5 ⎯⎯⎯⎯⎯⎯⎯
|
||||||
|
|
||||||
|
FAIL tests/App.test.tsx > 환경음 저작자·라이선스 고지를 같은 출처 링크로 제공한다
|
||||||
|
TestingLibraryElementError: Unable to find an accessible element with the role "link" and name "환경음 출처·라이선스"
|
||||||
|
|
||||||
|
Here are the accessible roles:
|
||||||
|
|
||||||
|
link:
|
||||||
|
|
||||||
|
Name "본문으로 건너뛰기":
|
||||||
|
[36m<a[39m
|
||||||
|
[33mclass[39m=[32m"skip-link"[39m
|
||||||
|
[33mhref[39m=[32m"#main"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "플레이 방법":
|
||||||
|
[36m<a[39m
|
||||||
|
[33mhref[39m=[32m"#howto"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
banner:
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<header[39m
|
||||||
|
[33mclass[39m=[32m"header wrap"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
heading:
|
||||||
|
|
||||||
|
Name "단어를 맞춰라":
|
||||||
|
[36m<h1 />[39m
|
||||||
|
|
||||||
|
Name "소음 속 작은 단어,들리시나요?":
|
||||||
|
[36m<h2[39m
|
||||||
|
[33mid[39m=[32m"hero-title"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "나의 소리 탐험 준비":
|
||||||
|
[36m<h2[39m
|
||||||
|
[33mid[39m=[32m"setup-title"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "작은 단어를 발견하는 방법":
|
||||||
|
[36m<h2[39m
|
||||||
|
[33mid[39m=[32m"howto-title"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "먼저, 귀 기울이기":
|
||||||
|
[36m<h3 />[39m
|
||||||
|
|
||||||
|
Name "기억한 단어 찾기":
|
||||||
|
[36m<h3 />[39m
|
||||||
|
|
||||||
|
Name "나의 발견 돌아보기":
|
||||||
|
[36m<h3 />[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
main:
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<main[39m
|
||||||
|
[33mclass[39m=[32m"wrap"[39m
|
||||||
|
[33mid[39m=[32m"main"[39m
|
||||||
|
[33mtabindex[39m=[32m"-1"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
region:
|
||||||
|
|
||||||
|
Name "소음 속 작은 단어,들리시나요?":
|
||||||
|
[36m<section[39m
|
||||||
|
[33maria-labelledby[39m=[32m"hero-title"[39m
|
||||||
|
[33mclass[39m=[32m"hero"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "나의 소리 탐험 준비":
|
||||||
|
[36m<section[39m
|
||||||
|
[33maria-labelledby[39m=[32m"setup-title"[39m
|
||||||
|
[33mclass[39m=[32m"setup-card"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "작은 단어를 발견하는 방법":
|
||||||
|
[36m<section[39m
|
||||||
|
[33maria-labelledby[39m=[32m"howto-title"[39m
|
||||||
|
[33mclass[39m=[32m"howto"[39m
|
||||||
|
[33mid[39m=[32m"howto"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
paragraph:
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p[39m
|
||||||
|
[33mclass[39m=[32m"eyebrow"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p[39m
|
||||||
|
[33mclass[39m=[32m"lead"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p[39m
|
||||||
|
[33mid[39m=[32m"snr-help"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<p />[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
emphasis:
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<em />[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
group:
|
||||||
|
|
||||||
|
Name "어떻게 답할까요?":
|
||||||
|
[36m<fieldset[39m
|
||||||
|
[33mclass[39m=[32m"mode-field"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
radio:
|
||||||
|
|
||||||
|
Name "골고루 풀기":
|
||||||
|
[36m<input[39m
|
||||||
|
[33maria-label[39m=[32m"골고루 풀기"[39m
|
||||||
|
[33mchecked[39m=[32m""[39m
|
||||||
|
[33mname[39m=[32m"mode"[39m
|
||||||
|
[33mtype[39m=[32m"radio"[39m
|
||||||
|
[33mvalue[39m=[32m"mixed"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "보기에서 선택":
|
||||||
|
[36m<input[39m
|
||||||
|
[33maria-label[39m=[32m"보기에서 선택"[39m
|
||||||
|
[33mname[39m=[32m"mode"[39m
|
||||||
|
[33mtype[39m=[32m"radio"[39m
|
||||||
|
[33mvalue[39m=[32m"choice"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "직접 입력":
|
||||||
|
[36m<input[39m
|
||||||
|
[33maria-label[39m=[32m"직접 입력"[39m
|
||||||
|
[33mname[39m=[32m"mode"[39m
|
||||||
|
[33mtype[39m=[32m"radio"[39m
|
||||||
|
[33mvalue[39m=[32m"text"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
strong:
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<strong />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<strong />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<strong />[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
combobox:
|
||||||
|
|
||||||
|
Name "배경 환경":
|
||||||
|
[36m<select[39m
|
||||||
|
[33mid[39m=[32m"environment"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "시작 난이도":
|
||||||
|
[36m<select[39m
|
||||||
|
[33mid[39m=[32m"starting-level"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
option:
|
||||||
|
|
||||||
|
Name "여덟 가지 일상 속으로":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"rotate"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "길거리":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"street"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "쇼핑몰":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"mall"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "극장":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"theater"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "백화점":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"department"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "시장":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"market"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "지하철":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"subway"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "카페":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"cafe"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "비 오는 거리":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"rain"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "1단계 · 소리에 익숙해지기 · SNR +6 dB":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"1"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "2단계 · 귀 기울이기 · SNR +3 dB":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"2"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "3단계 · 소음 사이로 · SNR 0 dB":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"3"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "4단계 · 작은 단서 찾기 · SNR -3 dB":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"4"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "5단계 · 깊이 집중하기 · SNR -6 dB":
|
||||||
|
[36m<option[39m
|
||||||
|
[33mvalue[39m=[32m"5"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
slider:
|
||||||
|
|
||||||
|
Name "목표 음성 SNR":
|
||||||
|
[36m<input[39m
|
||||||
|
[33maria-describedby[39m=[32m"snr-help"[39m
|
||||||
|
[33mid[39m=[32m"snr"[39m
|
||||||
|
[33mmax[39m=[32m"12"[39m
|
||||||
|
[33mmin[39m=[32m"-12"[39m
|
||||||
|
[33mstep[39m=[32m"1"[39m
|
||||||
|
[33mtype[39m=[32m"range"[39m
|
||||||
|
[33mvalue[39m=[32m"6"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "전체 음량":
|
||||||
|
[36m<input[39m
|
||||||
|
[33mid[39m=[32m"volume"[39m
|
||||||
|
[33mmax[39m=[32m"100"[39m
|
||||||
|
[33mmin[39m=[32m"0"[39m
|
||||||
|
[33mtype[39m=[32m"range"[39m
|
||||||
|
[33mvalue[39m=[32m"35"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
status:
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<output[39m
|
||||||
|
[33mfor[39m=[32m"snr"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<output[39m
|
||||||
|
[33mfor[39m=[32m"volume"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
button:
|
||||||
|
|
||||||
|
Name "게임 시작 · 소리 듣기":
|
||||||
|
[36m<button[39m
|
||||||
|
[33mclass[39m=[32m"primary"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
article:
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<article />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<article />[39m
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<article />[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
contentinfo:
|
||||||
|
|
||||||
|
Name "":
|
||||||
|
[36m<footer[39m
|
||||||
|
[33mclass[39m=[32m"footer wrap"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Ignored nodes: comments, script, style
|
||||||
|
[36m<body>[39m
|
||||||
|
[36m<div>[39m
|
||||||
|
[36m<a[39m
|
||||||
|
[33mclass[39m=[32m"skip-link"[39m
|
||||||
|
[33mhref[39m=[32m"#main"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m본문으로 건너뛰기[0m
|
||||||
|
[36m</a>[39m
|
||||||
|
[36m<header[39m
|
||||||
|
[33mclass[39m=[32m"header wrap"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"brand"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[33mclass[39m=[32m"brand-mark"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<h1>[39m
|
||||||
|
[0m단어를 맞춰라[0m
|
||||||
|
[36m</h1>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"version"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0mv0.2.3[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"header-actions"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<a[39m
|
||||||
|
[33mhref[39m=[32m"#howto"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m플레이 방법 [0m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m↓[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</a>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"little-dot"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[0m소리에 집중하는 시간[0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</header>[39m
|
||||||
|
[36m<main[39m
|
||||||
|
[33mclass[39m=[32m"wrap"[39m
|
||||||
|
[33mid[39m=[32m"main"[39m
|
||||||
|
[33mtabindex[39m=[32m"-1"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<section[39m
|
||||||
|
[33maria-labelledby[39m=[32m"hero-title"[39m
|
||||||
|
[33mclass[39m=[32m"hero"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"hero-copy"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<p[39m
|
||||||
|
[33mclass[39m=[32m"eyebrow"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span />[39m
|
||||||
|
[0m 귀를 기울이면, 발견하는 즐거움[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m<h2[39m
|
||||||
|
[33mid[39m=[32m"hero-title"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m소음 속 작은 단어,[0m
|
||||||
|
[36m<br />[39m
|
||||||
|
[36m<em>[39m
|
||||||
|
[0m들리시나요?[0m
|
||||||
|
[36m</em>[39m
|
||||||
|
[36m</h2>[39m
|
||||||
|
[36m<p[39m
|
||||||
|
[33mclass[39m=[32m"lead"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m도시의 소리 사이에 에스가 숨겨 둔 단어.[0m
|
||||||
|
[36m<br />[39m
|
||||||
|
[0m조금 더 귀 기울여, 오늘의 행운을 찾아보세요.[0m
|
||||||
|
[36m</p>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"hero-meta"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m한 라운드 [0m
|
||||||
|
[0m3[0m
|
||||||
|
[0m개의 질문[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m5단계 도전[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m나만의 속도로[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"sound-room"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"room-top"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[36m<i />[39m
|
||||||
|
[0m 에스의 사운드 룸[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<span>[39m
|
||||||
|
[0m8[0m
|
||||||
|
[0m가지 환경[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"orbit orbit-one"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"orbit orbit-two"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[33mclass[39m=[32m"floating-note note-one"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m♪[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[33mclass[39m=[32m"floating-note note-two"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m✳[0m
|
||||||
|
[36m</span>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"speech-bubble"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[0m행운의 단어를 찾아보거라![0m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[33mclass[39m=[32m"mascot "[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"ear left"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"ear right"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"eye left"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"eye right"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<span[39m
|
||||||
|
[33mclass[39m=[32m"smile"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<b>[39m
|
||||||
|
[0mS[0m
|
||||||
|
[36m</b>[39m
|
||||||
|
[36m</div>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33mclass[39m=[32m"room-bottom"[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<div[39m
|
||||||
|
[33maria-hidden[39m=[32m"true"[39m
|
||||||
|
[33mclass[39m=[32m"sound-wave "[39m
|
||||||
|
[36m>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 10px; animation-delay: 0s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 33.799955450859244px; animation-delay: 0.05s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 16.132986448643948px; animation-delay: 0.1s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 32.219552375865575px; animation-delay: 0.15000000000000002s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 21.858720427326595px; animation-delay: 0.2s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 29.163690702963766px; animation-delay: 0.25s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 26.796992502245015px; animation-delay: 0.30000000000000004s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 24.835290693688798px; animation-delay: 0.35000000000000003s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 30.619883556555898px; animation-delay: 0.4s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 35.39139668035928px; animation-delay: 0.45s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 71.52943948029164px; animation-delay: 0.5s;"[39m
|
||||||
|
[36m/>[39m
|
||||||
|
[36m<i[39m
|
||||||
|
[33mstyle[39m=[32m"height: 19.53593765210872px...
|
||||||
|
❯ Object.getElementError node_modules/@testing-library/dom/dist/config.js:37:19
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:76:38
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:52:17
|
||||||
|
❯ node_modules/@testing-library/dom/dist/query-helpers.js:95:19
|
||||||
|
❯ tests/App.test.tsx:420:17
|
||||||
|
418| it("환경음 저작자·라이선스 고지를 같은 출처 링크로 제공한다", () => {
|
||||||
|
419| fixture();
|
||||||
|
420| expect(screen.getByRole("link", { name: "환경음 출처·라이선스" })).toHaveAttr…
|
||||||
|
| ^
|
||||||
|
421| });
|
||||||
|
422|
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/5]⎯
|
||||||
|
|
||||||
|
FAIL tests/build.test.ts > 현장음 wav 손상은 빌드 실패로 처리한다
|
||||||
|
FAIL tests/build.test.ts > 현장음 manifest 손상은 빌드 실패로 처리한다
|
||||||
|
FAIL tests/build.test.ts > 현장음 notice 손상은 빌드 실패로 처리한다
|
||||||
|
FAIL tests/build.test.ts > 현장음 extra 손상은 빌드 실패로 처리한다
|
||||||
|
AssertionError: expected [Function verify] to throw an error
|
||||||
|
|
||||||
|
- Expected:
|
||||||
|
null
|
||||||
|
|
||||||
|
+ Received:
|
||||||
|
undefined
|
||||||
|
|
||||||
|
❯ tests/build.test.ts:76:20
|
||||||
|
74| if (damage === "notice") rmSync(join(temporary, "AMBIENCE_NOTICES.…
|
||||||
|
75| if (damage === "extra") writeFileSync(join(temporary, "ambience/or…
|
||||||
|
76| expect(verify).toThrow(/현장음/);
|
||||||
|
| ^
|
||||||
|
77| } finally { rmSync(temporary, {recursive: true, force: true}); }
|
||||||
|
78| });
|
||||||
|
|
||||||
|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/5]⎯
|
||||||
|
|
||||||
|
|
||||||
|
Test Files 2 failed (2)
|
||||||
|
Tests 5 failed | 21 skipped (26)
|
||||||
|
Start at 08:08:41
|
||||||
|
Duration 1.71s (tests 64%, environment 23%, setup 8%, transform 3%, import 2%)
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
> find-word@0.2.3 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-3VUCfIq1.js 247.59 kB │ gzip: 77.91 kB
|
||||||
|
|
||||||
|
✓ built in 178ms
|
||||||
|
빌드 음성 자산 101개 + 현장음 8개 및 런타임/현장음 notice 확인
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
> find-word@0.2.3 lint
|
||||||
|
> eslint . && tsc --noEmit
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
> find-word@0.2.3 lint
|
||||||
|
> eslint . && tsc --noEmit
|
||||||
|
|
||||||
|
src/App.tsx(249,54): error TS2367: This comparison appears to be unintentional because the types '"ready" | "loading" | "playing" | "answer" | "feedback"' and '"results"' have no overlap.
|
||||||
|
src/App.tsx(250,16): error TS2367: This comparison appears to be unintentional because the types '"ready" | "loading" | "playing" | "answer" | "feedback"' and '"results"' have no overlap.
|
||||||
|
tests/audio.test.ts(284,95): error TS2352: Conversion of type '(value: { duration: number; length: number; sampleRate: number; numberOfChannels: number; getChannelData: () => Float32Array<ArrayBuffer>; copyToChannel: Mock<(samples: Float32Array<...>) => void>; } | PromiseLike<...>) => void' to type '(buffer: AudioBuffer) => void' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
|
||||||
|
Types of parameters 'value' and 'buffer' are incompatible.
|
||||||
|
Type 'AudioBuffer' is not comparable to type '{ duration: number; length: number; sampleRate: number; numberOfChannels: number; getChannelData: () => Float32Array<ArrayBuffer>; copyToChannel: Mock<(samples: Float32Array<ArrayBufferLike>) => void>; } | PromiseLike<...>'.
|
||||||
|
Type 'AudioBuffer' is not comparable to type '{ duration: number; length: number; sampleRate: number; numberOfChannels: number; getChannelData: () => Float32Array<ArrayBuffer>; copyToChannel: Mock<(samples: Float32Array) => void>; }'.
|
||||||
|
Types of property 'getChannelData' are incompatible.
|
||||||
|
Type '(channel: number) => Float32Array<ArrayBuffer>' is not comparable to type '() => Float32Array<ArrayBuffer>'.
|
||||||
|
Target signature provides too few arguments. Expected 1 or more, but got 0.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
> find-word@0.2.3 test:browser
|
||||||
|
> playwright test tests/browser/release.spec.ts
|
||||||
|
|
||||||
|
[WebServer] (node:810785) 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:810805) 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:810806) 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/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다 (76ms)
|
||||||
|
✓ 1 [desktop] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (582ms)
|
||||||
|
(node:810893) 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:810963) 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)
|
||||||
|
✓ 3 [mobile] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (589ms)
|
||||||
|
✓ 4 [mobile] › tests/browser/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다 (75ms)
|
||||||
|
|
||||||
|
4 passed (2.8s)
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
> find-word@0.2.3 test:browser
|
||||||
|
> playwright test tests/browser/release.spec.ts
|
||||||
|
|
||||||
|
[WebServer] (node:810330) 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:810350) 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:810351) 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/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다 (65ms)
|
||||||
|
✓ 1 [desktop] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (571ms)
|
||||||
|
(node:810452) 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:810501) 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)
|
||||||
|
✓ 3 [mobile] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (607ms)
|
||||||
|
✘ 4 [mobile] › tests/browser/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다 (64ms)
|
||||||
|
|
||||||
|
|
||||||
|
1) [desktop] › tests/browser/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다
|
||||||
|
|
||||||
|
Error: expect(received).toBe(expected) // Object.is equality
|
||||||
|
|
||||||
|
Expected: 404
|
||||||
|
Received: 200
|
||||||
|
|
||||||
|
25 | for (const directory of ["audio", "ambience"]) {
|
||||||
|
26 | const response = await request.get(`/${directory}/not-found.wav?v=0.2.3`, { headers: { Accept: "text/html" } });
|
||||||
|
> 27 | expect(response.status()).toBe(404);
|
||||||
|
| ^
|
||||||
|
28 | expect(await response.text()).not.toContain('<div id="root">');
|
||||||
|
29 | }
|
||||||
|
30 | const notice = await request.get("/AMBIENCE_NOTICES.md");
|
||||||
|
at /home/hermes/worktrees/find-word-v0.2.3/tests/browser/release.spec.ts:27:31
|
||||||
|
|
||||||
|
Error Context: test-results/release-누락-음성·환경음은-query와-HTML-accept에도-404이고-출처-고지는-번들된다-desktop/error-context.md
|
||||||
|
|
||||||
|
attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
|
||||||
|
test-results/release-누락-음성·환경음은-query와-HTML-accept에도-404이고-출처-고지는-번들된다-desktop/trace.zip
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
npx playwright show-trace test-results/release-누락-음성·환경음은-query와-HTML-accept에도-404이고-출처-고지는-번들된다-desktop/trace.zip
|
||||||
|
|
||||||
|
────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
2) [mobile] › tests/browser/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다
|
||||||
|
|
||||||
|
Error: expect(received).toBe(expected) // Object.is equality
|
||||||
|
|
||||||
|
Expected: 404
|
||||||
|
Received: 200
|
||||||
|
|
||||||
|
25 | for (const directory of ["audio", "ambience"]) {
|
||||||
|
26 | const response = await request.get(`/${directory}/not-found.wav?v=0.2.3`, { headers: { Accept: "text/html" } });
|
||||||
|
> 27 | expect(response.status()).toBe(404);
|
||||||
|
| ^
|
||||||
|
28 | expect(await response.text()).not.toContain('<div id="root">');
|
||||||
|
29 | }
|
||||||
|
30 | const notice = await request.get("/AMBIENCE_NOTICES.md");
|
||||||
|
at /home/hermes/worktrees/find-word-v0.2.3/tests/browser/release.spec.ts:27:31
|
||||||
|
|
||||||
|
Error Context: test-results/release-누락-음성·환경음은-query와-HTML-accept에도-404이고-출처-고지는-번들된다-mobile/error-context.md
|
||||||
|
|
||||||
|
attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
|
||||||
|
test-results/release-누락-음성·환경음은-query와-HTML-accept에도-404이고-출처-고지는-번들된다-mobile/trace.zip
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
npx playwright show-trace test-results/release-누락-음성·환경음은-query와-HTML-accept에도-404이고-출처-고지는-번들된다-mobile/trace.zip
|
||||||
|
|
||||||
|
────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
2 failed
|
||||||
|
[desktop] › tests/browser/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다
|
||||||
|
[mobile] › tests/browser/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다
|
||||||
|
2 passed (2.9s)
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
> find-word@0.2.3 test:browser
|
||||||
|
> playwright test
|
||||||
|
|
||||||
|
[WebServer] (node:811225) 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 24 tests using 2 workers
|
||||||
|
|
||||||
|
(node:811278) 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:811277) 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 › 음성·현장음 109개 versioned WAV를 실제 Chrome에서 해시·디코드 검증한다 (18.5s)
|
||||||
|
✓ 3 [desktop] › tests/browser/game.spec.ts:130:3 › intro WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (12.6s)
|
||||||
|
✓ 2 [desktop] › tests/browser/game.spec.ts:8:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 (40.4s)
|
||||||
|
✓ 5 [desktop] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (454ms)
|
||||||
|
✓ 6 [desktop] › tests/browser/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다 (28ms)
|
||||||
|
✓ 4 [desktop] › tests/browser/game.spec.ts:130:3 › target WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (17.1s)
|
||||||
|
✓ 8 [desktop] › tests/browser/rounds.spec.ts:84:1 › 여덟 환경의 실제 WAV를 각각 디코드하고 루프 재생한 뒤 즉시 정지한다 (8.0s)
|
||||||
|
✓ 9 [desktop] › tests/browser/rounds.spec.ts:112:1 › 환경음 404는 한국어 오류와 재시도 후 정상 답변으로 복구한다 (16.2s)
|
||||||
|
✓ 10 [desktop] › tests/browser/ui.spec.ts:4:1 › 전체 음량은 설정 흐름 안에 들어가며 키보드로 조절된다 (1.6s)
|
||||||
|
✓ 11 [desktop] › tests/browser/ui.spec.ts:52:1 › 난이도 설명은 모바일에서도 보인다 (1.1s)
|
||||||
|
✓ 12 [desktop] › tests/browser/ui.spec.ts:68:1 › 한국어 제목은 단어 중간에서 줄바꿈하지 않는다 (17.5s)
|
||||||
|
(node:812211) 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)
|
||||||
|
✓ 7 [desktop] › tests/browser/rounds.spec.ts:29:1 › 시작 단계·SNR·3문항 완료→다음 단계·재생 중 종료·응답 후 종료·홈 초기화 (1.1m)
|
||||||
|
(node:812418) 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)
|
||||||
|
✓ 13 [mobile] › tests/browser/audio.spec.ts:7:1 › 음성·현장음 109개 versioned WAV를 실제 Chrome에서 해시·디코드 검증한다 (16.1s)
|
||||||
|
✓ 15 [mobile] › tests/browser/game.spec.ts:130:3 › intro WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (17.2s)
|
||||||
|
✓ 16 [mobile] › tests/browser/game.spec.ts:130:3 › target WAV query URL의 404를 표시하고 같은 URL로 재시도·정답 mapping한다 (12.6s)
|
||||||
|
✓ 17 [mobile] › tests/browser/release.spec.ts:6:1 › 릴리스는 사용자 크레딧과 런타임 MIT notice 전문을 제공한다 (306ms)
|
||||||
|
✓ 18 [mobile] › tests/browser/release.spec.ts:24:1 › 누락 음성·환경음은 query와 HTML accept에도 404이고 출처 고지는 번들된다 (20ms)
|
||||||
|
✓ 14 [mobile] › tests/browser/game.spec.ts:8:1 › 실제 오디오로 혼합 모드 완주·레이아웃·접근성·외부 요청 없음 (37.7s)
|
||||||
|
✓ 20 [mobile] › tests/browser/rounds.spec.ts:84:1 › 여덟 환경의 실제 WAV를 각각 디코드하고 루프 재생한 뒤 즉시 정지한다 (6.1s)
|
||||||
|
✓ 21 [mobile] › tests/browser/rounds.spec.ts:112:1 › 환경음 404는 한국어 오류와 재시도 후 정상 답변으로 복구한다 (16.0s)
|
||||||
|
✓ 22 [mobile] › tests/browser/ui.spec.ts:4:1 › 전체 음량은 설정 흐름 안에 들어가며 키보드로 조절된다 (834ms)
|
||||||
|
✓ 23 [mobile] › tests/browser/ui.spec.ts:52:1 › 난이도 설명은 모바일에서도 보인다 (637ms)
|
||||||
|
✓ 24 [mobile] › tests/browser/ui.spec.ts:68:1 › 한국어 제목은 단어 중간에서 줄바꿈하지 않는다 (17.0s)
|
||||||
|
✓ 19 [mobile] › tests/browser/rounds.spec.ts:29:1 › 시작 단계·SNR·3문항 완료→다음 단계·재생 중 종료·응답 후 종료·홈 초기화 (57.4s)
|
||||||
|
|
||||||
|
24 passed (3.4m)
|
||||||