Files
Find-Word/docs/AUDIO_PROVENANCE.md
T

319 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Find-Word v0.2.5 오디오 출처와 재현
## 포함 자산과 생성 설정
| 대상 | 생성 방식 | 원문/설정 | 배포 방식 |
| --- | --- | --- | --- |
| `public/audio/intro.wav` | Microsoft Edge online TTS neural 음성 | `src/content.ts`의 INTRO | 24kHz mono PCM16 WAV |
| 목표 음성 100개 | 같은 provider·voice | 10 패턴 × 10 단어, `renderSentence` | 같은 WAV |
| 8개 배경 환경 | 공개 라이선스 실제 현장 녹음 | `public/ambience/manifest.json` | 12초·24kHz mono PCM16 WAV |
| 화면 파형·S 캐릭터 | 직접 작성한 CSS | `App.tsx`, `styles.css` | CSS |
voice는 **`ko-KR-HyunsuMultilingualNeural`**, rate는 **`-6%`**, pitch는
**`-4Hz`**, 생성 클라이언트는 **edge-tts 7.3.1**이다. 직접 작성한 한국어
문장을 온라인 provider에 보내 MP3 응답을 받은 뒤 FFmpeg로 PCM을 만든다.
음성 복제나 사람의 녹음 샘플을 사용하지 않는다. 웃음은 INTRO의 ‘으하하하~~’를
같은 voice로 합성한다. 앱은 저장한 WAV만 같은 출처에서 가져오며 런타임 외부
TTS/API, speechSynthesis, 인증정보가 필요하지 않다.
청취용 샘플은 [intro.wav](../public/audio/intro.wav)와
[luck-apple.wav](../public/audio/luck-apple.wav)이다. 101개 전체 생성 결과의
크기·길이 범위와 독립 검증은 [v0.1.1 RESULT](../.agent/RESULT-v0.1.1.md)에 기록한다.
`public/audio/manifest.json`은 version, provider, voice, rate, pitch, sampleRate,
생성 시각, 실측 edge-tts/FFmpeg 버전, 파일별 원문·SHA-256·bytes·duration·RMS·peak를 담는다.
## 설치와 생성
생성 환경은 Linux (기존 디렉터리 교체에 `renameat2(RENAME_EXCHANGE)` 필요),
Python 3.11 이상, FFmpeg, Node.js 22.22.2 이상이다. **이미 포함된 WAV를
빌드·실행할 때는 Python/FFmpeg/provider 연결이 필요 없다.** 생성기 계약 테스트는
Python과 FFmpeg를 사용하되 네트워크 없이 동작한다.
```bash
python3 -m venv .venv-audio
.venv-audio/bin/python -m pip install -r requirements-audio.txt
.venv-audio/bin/python -m pip check
npm run audio:generate
npm test
npm run build
```
`audio:generate`는 `.venv-audio/bin/python scripts/generate_audio.py`로 고정되어
전역 Python으로 대체되지 않는다. `requirements-audio.txt`는 edge-tts==7.3.1과
전이 의존성 버전을 고정한다. 생성기는 실제 설치 버전을 조회하고 7.3.1이 아니면
외부 요청 전에 실패한다. `.venv-audio/`는 Git과 배포물에서 제외한다.
원문을 Node type stripping으로 앱 데이터에서 읽고, 101개 모두 같은 파일시스템의
`public/.audio-stage-*/`에 순차 생성한다. 각 provider 요청은 최대 60초, 최대
3회 시도이며 실패 사이 1초/2초를 기다린다. FFmpeg도 60초 제한이 있다.
재시도 전 불완전 MP3를 삭제하고 변환·검증 실패는 즉시 중단한다. 로그에는
파일명·시도 횟수만 남기고 provider stderr/응답·쿠키·인증 헤더를 저장하지 않는다.
전체 WAV와 manifest를 검증한 뒤 기존 `public/audio`와 완성 디렉터리를 단일
원자 교환으로 바꾼다. 실패·Ctrl-C는 기존 디렉터리의 바이트를 그대로 보존한다.
원자 교환을 지원하지 않는 파일시스템에서는 실패하며 비원자 방식으로 우회하지 않는다.
성공 후 이전 자산과 임시 MP3를 정리한다. 강제 종료(SIGKILL)·전원 손실 때는
숨김 staging 폴더가 남을 수 있으나 공개 디렉터리는 교환 전 또는 후의 전체 집합이다.
이는 전원 손실 시 저장장치 내구성 보장을 뜻하지 않는다.
고정 클라이언트와 설정으로 **생성 절차**를 재현할 수 있다. 원격 모델·서비스 버전은
고정할 수 없어 재생성 WAV의 바이트 동일성은 보장하지 않는다. 새 실행의 manifest를
검토해야 한다. 빌드는 이미 생성한 WAV의 해시를 보존하고 101개 모두 포함됐는지 확인한다.
## 레벨 처리와 검증
MP3를 24kHz mono signed 16-bit little-endian PCM으로 디코드한다. 파일 전체에
동일한 선형 gain을 적용해 RMS 0.10을 목표로 하며 증폭은 최대 2배, peak는
0.89로 제한한다. 동적 압축·노이즈 게이트·침묵 제거·시간 변형은 하지 않는다.
원래 신호의 자음과 억양을 보존하면서 파일 간 레벨 차이와 피크를 완화한다.
생성기와 독립 자산 테스트는 101개 파일의 원문·집합·SHA-256·bytes·duration,
24kHz mono PCM16, 1–20초 길이, RMS > 100/32768, full-scale 미도달,
총 48MiB 미만을 검사한다. 기존 음성 단독 검사는 RMS 0.03과 +6dB에서 peak < 0.8을
요구한다. v0.2.5 최대 +12dB 혼합은 [고정 headroom 수식](ARCHITECTURE.md#오디오)으로 별도 검증한다.
앱은 voice/intro의 RMS 정규화를 유지하고 배경 loudness 정규화 PCM을 그대로 쓴다.
물리적 음압이나 주파수별 청감을 보정한 값은 아니다.
## 도구 라이선스와 서비스 조건
- [edge-tts 7.3.1 LICENSE](https://github.com/rany2/edge-tts/blob/7.3.1/LICENSE):
대부분의 코드에 LGPLv3, `srt_composer.py`에만 MIT가 적용된다.
[공식 프로젝트](https://github.com/rany2/edge-tts)는 Microsoft Edge의 온라인
TTS를 이용하는 클라이언트다. 클라이언트 라이선스가 provider 사용·음성 출력의
재배포 권한을 대신 부여하지 않는다. 이 프로젝트는 클라이언트/모델을 번들하지 않는다.
- [FFmpeg 공식 라이선스](https://ffmpeg.org/legal.html): 빌드 옵션에 따라 LGPL/GPL이
적용된다. 실제 사용 버전은 manifest에 남기며 실행 파일은 배포하지 않는다.
- [Microsoft Services Agreement](https://www.microsoft.com/en-us/servicesagreement)의
AI Services 등 해당 서비스 조건은 도구의 오픈소스 라이선스와 별개다.
위 문서 §13(s)(vi)는 출력의 권리·사용 가능성을 이용자가 판단하도록 설명한다.
API 키 없이 호출된다는 사실이 상업 사용·재배포의 포괄적 허락이나 SLA를 뜻하지 않는다.
배포자는 자신의 이용 상황에 적용되는 최신 조건을 확인해야 한다.
- 프로젝트는 생성 음성 자체에 **독점 권리를 주장하지 않는다**. [LICENSE](../LICENSE)의
소스·문서 권리 유보와 provider 및 제3자의 권리는 구분한다. 런타임 React,
ReactDOM, scheduler의 MIT 전문은 [THIRD_PARTY_NOTICES.md](../THIRD_PARTY_NOTICES.md)에 있다.
문서 확인일: 2026-10-14 UTC. provider의 음성 목록, rate/pitch 지원, 가용성,
접근 제한, 조건은 바뀔 수 있다. 온라인 생성이 중단되어도 포함된 WAV의 빌드·재생에는
영향이 없다. 실패 시 다른 voice로 자동 대체하지 않는다.
## 청감과 평가의 한계
자동 검증은 PCM 신호·무결성·재생 흐름을 확인한다. 한국어 발음, 유사 자모의
구분, 웃음의 자연스러움과 실제 사용자의 난이도는 청취 평가가 필요하다.
대표 샘플과 게임 내 소음 혼합 상태를 직접 들어 인수 판단한다. 배경은 실제 현장 녹음의 짧은 구간이다. 이 게임의 수치는 임상 검증·치료·청력 판정용이 아니다.
## v0.2.5 loudness 정규화
**exact 자산 소유자 승인:** loudness 수정은 두 계기를 통과했다. 새 market WAV의 동일 VAD ASR 조건은
여전히 실패하며, 릴리스는 아래 Oz의 새 exact-byte 청취 승인 경로로만 수용한다. 법적/privacy clearance는 없다.
기존 loudnorm input_i의 0.01 LU spread는 같은 파일의 전용 ebur128 **2.0 LU**, 독립 pyloudnorm 0.2.0
**1.925 LU** 결과에 의해 거부되었다. loudnorm input_i를 수용 계기로 인정하지 않는다.
[거부된 당시 RESULT](../.agent/evidence-v0.2.5/review-fixes/rejected-RESULT-v0.2.5.md),
[기존 원문 측정](../.agent/evidence-v0.2.5/independent-loudness.json)과 기존 증거 전체는 불변 역사다.
원본 8개 SHA-256/bytes·creator·license·attribution·선택 구간을 모두 보존했다.
[정규화 계획](../.agent/AMBIENCE-NORMALIZATION-v0.2.5.json)은 불변 source plan의 SHA-256을 포함한다.
도구는 **ffmpeg version 6.1.1-3ubuntu5**이며 일반 회귀 검사는 Python 표준 라이브러리와 FFmpeg만 사용한다.
1. 원본 전체의 hash/bytes를 검증한 뒤 기존 seek/full decode sample trim으로 승인 구간을 추출한다.
2. 24kHz mono float PCM 288,000 samples에 기존 양끝 50ms 선형 fade를 적용한다.
3. 정확한 faded PCM을 새 `ebur128=peak=true` 프로세스로 측정하고 **gain_db=−32.5−measured_i**를 계산한다.
4. **measured_true_peak+gain_db > −6.2 dBTP**면 변환 전에 실패한다. market의 파형을 보존할 수 있도록
공통 목표를 −32.5 LUFS로 선택했다. −6.2 내부 ceiling은 최종 −6 dBTP 조건에 0.2 dB 여유를 둔다.
5. 같은 PCM에 오직 `volume=<gain_db>dB:precision=double`을 적용하고 FFmpeg `pcm_s16le`로 인코딩한다.
표준 `wave` writer는 44-byte WAV 헤더를 쓴다. compressor/limiter/loudnorm은 사용하지 않는다.
6. staged WAV 전체를 새 ebur128 프로세스로 측정한다. 목표 오차가 ±0.2 LU 밖일 때만 원래 faded PCM에서
스칼라를 보정한다. 최대 총 3회, 매 시도 peak 사전 검사를 수행하고 비수렴은 실패한다.
7. 전체 staging의 형식/길이/fade/출처/notice/hash를 검증하고 ebur128을 다시 실행한다.
**목표 ±0.2 LU, spread ≤0.4 LU, true peak ≤−6 dBTP**를 강제한다. 생성 중에는 −6.2도 강제한다.
전부 통과한 8 WAV·manifest·고지를 단일 `renameat2(RENAME_EXCHANGE)`로 교환한다.
source mismatch·NaN·측정/쓰기/교환 실패·목표/peak 위반은 이전 공개 디렉터리를 보존한다.
manifest `normalization`에는 목표/허용오차/spread/두 ceiling/계기/최대 반복 수가 있고,
`toolVersions.ffmpeg`에는 실제 도구 버전이 있다. 각 `conversion.loudness`는 faded PCM hash,
입력 ebur128 통계, 매 iteration의 정확한 gain/filter/예측 peak/출력 통계와 최종 통계를 보존한다.
이번 8개는 모두 **첫 시도에 수렴**하여 보정 반복이 필요하지 않았다.
| 환경 | 원본 구간(초) | 입력 LUFS | gain dB | 최종 LUFS | true peak dBTP | sample peak |
| --- | --- | --- | --- | --- | --- | --- |
| street | 35–47 | -35.7 | 3.2 | -32.5 | -10.2 | 0.31008911 |
| mall | 36–48 | -22.1 | -10.4 | -32.5 | -12.2 | 0.23022461 |
| theater | 45–57 | -25.7 | -6.8 | -32.5 | -16.1 | 0.15737915 |
| department | 90–102 | -24.1 | -8.4 | -32.5 | -16.6 | 0.14721680 |
| market | 24–36 | -26.4 | -6.1 | -32.5 | -6.2 | 0.47195435 |
| subway | 65–77 | -16.5 | -16.0 | -32.5 | -16.2 | 0.15432739 |
| cafe | 0–12 | -19.5 | -13.0 | -32.5 | -18.2 | 0.12213135 |
| rain | 180–192 | -52.2 | 19.7 | -32.5 | -12.1 | 0.24734497 |
최종 전용 ebur128: **−32.5 LUFS 전수, spread 0.0 LU**, 최대 true peak **−6.2 dBTP**.
생성기를 import하지 않는 [독립 회귀 테스트](../tests/python/test_loudness_audio.py)가 이 동등성을 강제한다.
별도 disposable **pyloudnorm 0.2.0 / soundfile 0.13.1**의 exact-WAV 측정은
**−32.6062~−32.5291 LUFS, spread 0.0772 LU**, 최대 목표 오차 **0.1063 LU 미만**으로 통과했다.
[결과/스크립트/고정 의존성과 해시](../.agent/evidence-v0.2.5/review-fixes/README.md)를 별도로 보존한다.
일반 npm test는 이 패키지 설치나 네트워크가 필요 없다. 같은 FFmpeg/입력/플랫폼에서 두 번 다시 생성한
WAV/notice/측정 통계의 재현성도 검사했다. manifest의 생성 시각만 달라진다.
```bash
python3 scripts/ambience_audio.py
python3 -m unittest discover -s tests/python -v
```
[새 exact-WAV ASR 결과](../.agent/evidence-v0.2.5/review-fixes/final-asr.json)는 동일한
faster-whisper **1.2.1**, tiny revision `d90ca5fe260221311c53c58e660288d3deb8d356`, CPU int8,
beam_size=5, best_of=5, 기본 Silero VAD, condition_on_previous_text=true를 사용했다.
**market 1 segment, mall/cafe 0개, requiredEmptyPassed=false**다. market hash는
`7178307c48c192ac396dcd3c880c377bf56b45e829b459b1feca9f986437e632`이다.
반환 구간 10.45–12.45초와 텍스트 ` Let's go, let's go, let's go.`를 수정 없이 보존했다.
텍스트는 검증된 전사가 아니며 환각일 수 있다. ASR 원문 SHA-256
`98acdb16bc5dce57bb3609b705b63125e5511c2d5f7b26bdde54f4b7bd9a5e49`와 모든 설정/segment를 보존한다.
ASR 보고서 자체의 **humanListeningAcceptance=false, legalPrivacyClearance=false**도 변경하지 않는다.
제품 소유자 Oz는 `/home/hermes/voice-memos/find-word-v0.2.5-normalized-ambience-review.zip`의
현재 8 WAV·manifest·notice를 받은 뒤 **“승인합니다. 이대로 진행하세요”**라고
**2026-10-14T11:29:51Z / 2026-10-14 20:29:51 KST**에 회신했다. 사용자가 전달한 이 새 회신은
별도 [RELEASE-APPROVAL](../.agent/RELEASE-APPROVAL-v0.2.5.json)에 기록한다.
ZIP SHA-256은 `bb2e974b652df43db4a1f2a59716836e2c521839c724b34d4b71c1b40c3322e5`,
현재 manifest SHA-256은 `6433bf23af35f24031c6bbe784dd0abf9330f276da6b8705e47c7a1144a285b7`이며
모든 WAV/notice 해시도 기록했다. 이 별도 인수 기록은 **productOwnerReleaseApproval=true,
humanListeningAcceptance=true, legalPrivacyClearance=false**다. 법적/privacy clearance나 ASR의 PASS를 주장하지 않는다.
`python3 scripts/release_approval.py`는 동일 설정의 자동 empty-ASR 조건 **OR** 유효한 exact-byte 소유자
청취 승인을 요구한다. 현재 통과 사유는 후자뿐이다. 승인 문구/범위/시각/소유자/flags와 고정 ZIP hash를
검사하고 ZIP의 manifest·notice·8 WAV를 현재 파일과 바이트 단위로 비교한다. 다른 자산/manifest/ZIP,
필수 정보 누락, 법적 clearance 과장은 거부한다. 원래 실패 테스트·실패 로그는
[release-approval 증거](../.agent/evidence-v0.2.5/release-approval/README.md)에 보존하며
현재 회귀 테스트는 원문 실패의 불변성과 별도 승인 계약을 각각 검사한다. 이전 v0.2.3 승인의 범위는 그대로다.
## v0.2.3 현장 녹음 파생본 — 역사 기록
아래 절의 “현재/최종”은 v0.2.3 당시 상태를 뜻한다. 당시 exact manifest/WAV는
[v0.2.3 snapshot](../.agent/evidence-v0.2.5/baseline/ambience/)에 보존했고 원본 evidence는 수정하지 않았다.
원본 선정 계약은 [.agent/AMBIENCE-SOURCES-v0.2.3.json](../.agent/AMBIENCE-SOURCES-v0.2.3.json),
배포 바이트의 출처·직접 URL·저작자·라이선스·변환·SHA-256·bytes·duration·RMS·peak는
[manifest](../.agent/evidence-v0.2.5/baseline/ambience/manifest.json), 정확한 attribution과 변경 고지는
[AMBIENCE_NOTICES](../.agent/evidence-v0.2.5/baseline/ambience/AMBIENCE_NOTICES.md)에 있다. 이 고지는 dist에도 포함되고 UI에서 링크한다.
여덟 원본 모두 서로 다른 현장 녹음이며 NC/ND 자산을 사용하지 않는다. 원본은 저장소/빌드에 포함하지 않는다.
| 환경 | 저작자 | 라이선스 | 원본 구간(초) |
| --- | --- | --- | --- |
| 길거리 | cori (Cori Samuel) | PD-author | 35–47 |
| 쇼핑몰 | thore (Thore) | PD-author | 36–48 |
| 극장 | ElevatorFan2020 | CC0 1.0 | 45–57 |
| 백화점 | icmusic | CC0 1.0 | 90–102 |
| 시장 | Marie Flutre | CC BY-SA 4.0 | 24–36 |
| 지하철 | PascalHD | CC BY 4.0 | 65–77 |
| 카페 | Marble Toast | CC0 1.0 | 0–12 |
| 비 오는 거리 | Extemporalist | CC0 1.0 | 180–192 |
Commons primary 페이지/API와 Freesound primary 페이지의 라이선스 근거를 evidence에 보존한다.
Freesound 두 원본은 지정된 preview MP3이다. 프로젝트의 비공개 라이선스를 제3자 녹음에
적용하지 않으며, 시장 파생 WAV는 **CC BY-SA 4.0**으로 계속 공개·수정·재배포할 수 있다.
지하철은 **CC BY 4.0**의 PascalHD credit·변경 고지·라이선스 링크를 유지한다.
재현: 검증한 원본 8개를 `/tmp/findword-ambience-sources`에 놓고
`python3 scripts/ambience_audio.py`를 실행한다. 계획의 파일별 `selectedSegmentStartSeconds`에서 12초를 선택하고,
FFmpeg로 mono 24kHz float PCM 디코드 후 양끝 50ms 선형 fade, RMS 목표 .08,
최대 증폭 4배/peak .85 중 가장 작은 선형 gain을 적용한다. 마지막은 표준 44-byte
WAV 헤더의 PCM16이다. 시간 변형·절차적 합성·원본 음성 대체는 없다.
원본 SHA-256과 실측 FFmpeg 버전을 함께 기록하므로 같은 원본/도구로 재현 가능하다.
런타임은 음성/배경 각각 RMS .03 후 상대 gain `10^(dB/20)`을 적용한다. −12~+12 dB
범위에서도 세 경로의 최악 피크 합을 공통 감쇠하여 최대 .8로 제한한다. 양끝 fade가
있는 배경을 loop하고 목표 끝에서 정리한다. 전체 버퍼 RMS 기준이며 짧은 시간창별
SNR이나 실제 음압을 보증하지 않는다. 원본 녹음의 우연한 사람 말소리는 환경의 일부다.
자동 검사로 음악·개인 대화의 완전한 부재를 인증할 수 없으므로 사람의 최종 청취 검토가 필요하다.
기존 neural WAV 101개의 원문·해시는 v0.1.1 그대로다. 음성 manifest의 version은
배포 버전 0.2.3, `generatedForVersion`은 0.1.1이며 원래 생성 시각·도구 정보는 보존한다.
### 리뷰 후 출처 고정과 원자 발행
승인 계획의 `expectedSourceSha256`와 `sourceBytes`는 불변 입력이다. 생성기는 로컬 경로나
현재 파일에서 이 승인값을 새로 기록하지 않으며, 여덟 원본의 해시·크기를 **첫 변환 전**에 모두 검사한다.
한 원본이라도 다르거나 누락되면 실패한다. `sourceVerification`은 검증 상태·일자·방법·보존된 증거를 가리킨다.
임시 경로를 담던 `verifiedLocalSource` 필드는 제거했다.
`directMediaDurationSeconds`는 **directUrl에서 받은 바로 그 바이트**의 ffprobe `format.duration`이다.
Freesound 항목은 preview MP3의 길이이며 primary 페이지 원본 길이 또는 반올림한 표시 길이가 아니다.
배포 manifest의 `duration`과 `conversion.durationSeconds`는 파생 WAV의 길이(12초),
`selectedSegmentStartSeconds`는 파일별 불변 승인 시작점이며 생성기는 별도 hardcoded map 없이 이 값을 읽는다.
`conversion.startSeconds`는 같은 값이어야 한다. 시작점은 유한한 0 이상 수이고, 시작점+12초가
`directMediaDurationSeconds` 이하여야 한다. 누락·음수·NaN·Infinity·문자열·bool·범위 초과는 첫 변환 전에 거부한다. 원본 전체 디코드와 실제 수치는
[보존된 source-integrity.json](../.agent/evidence-v0.2.3/source-integrity.json)에 있다.
생성기는 출력 폴더와 같은 부모의 `.ambience-stage-*/ready`에서 8 WAV·manifest·`AMBIENCE_NOTICES.md`를
완성한다. 정확한 파일 집합, 고유 해시, 원본 계획, PCM 형식·길이·fade·RMS·peak,
항목별 저작자/primary URL/direct URL/라이선스 링크/outputLicense/변경 설명을 다시 검사한다.
존재하는 symlink 및 dangling symlink 출력을 모두 거부한다. Linux `renameat2(RENAME_EXCHANGE)` 한 번이 교체의
commit 지점이며, 최초 생성은 같은 파일시스템의 rename 한 번이다. 지원하지 않는 환경에서는 실패한다.
파일별 overlay를 하지 않으므로 오래된 파일이 남지 않고 고지도 음원과 같은 디렉터리로 교체된다.
commit 전 변환·쓰기·검증·교환 실패 또는 중단은 이전 디렉터리를 보존한다. syscall 이후에는 완성된 새 디렉터리가
공개된 상태다. SIGKILL 등 강제 종료는 숨은 임시 디렉터리를 남길 수 있지만 부분 배포는 만들지 않는다.
전원 손실에 대한 디스크 내구성이나 여러 HTTP 요청에 걸친 snapshot 격리를 주장하지 않는다.
앞선 독립 리뷰에서는 기존 109 WAV를 재생성하지 않았다. 이후 아래 privacy refinement에서
전체 현장음 bundle을 원자 재생성했으며 mall/market/cafe 3개만 바이트가 바뀌었다.
**사람의 현장음 청취 인수는 미실행**이다.
### 최종 privacy excerpt refinement
현재 선택은 **mall 36–48초, market 24–36초, cafe 0–12초**다. Neo가 동일한
`scripts/ambience_audio.convert` 경로와 아래 ASR 설정으로 해시 고정 원본을 재검사해 제시한
market/cafe 후보를 사용했다. 제공받은 재검사 설명은
[selection-context.json](../.agent/evidence-v0.2.3/privacy-screening/retry-market24-cafe0/selection-context.json)에
별도로 기록했으며, 원본 후보 결과를 최종 WAV 검사 결과로 대신하지 않았다.
승인 원본 8개의 SHA-256·bytes·ffprobe 길이를 먼저 대조하고 하드닝된 생성기로
8 WAV·manifest·notice 전체를 staging/검증/원자 교환했다.
[생성 실측 기록](../.agent/evidence-v0.2.3/privacy-screening/retry-market24-cafe0/regeneration.json)에
현재 해시·RMS·peak·변환이 있다. 이번 재시도는 market/cafe 두 WAV만 변경했다.
**101개 voice, 다섯 unaffected ambience, 기존 mall 36초 WAV는 모두 바이트 동일**하다.
일부 Ogg 구간은 FFmpeg timestamp/seek 때문에 12초보다 몇 프레임 짧게 출력된다.
짧은 결과일 때만 처음부터 디코드한 24kHz PCM의 `round(start × 24000)`부터 정확한 288,000개
sample을 선택하고 출력 PTS를 sample 수로 재설정한다. silent padding이나 time stretching은 없다.
정말 원본이 짧으면 여전히 실패하며 `conversion.seekMethod`가 실제 경로를 기록한다.
[final-asr.json](../.agent/evidence-v0.2.3/privacy-screening/final-asr.json)은 정확한 현재 8 WAV를
로컬 **faster-whisper 1.2.1, tiny multilingual, CPU int8, beam_size=5, best_of=5,
기본 Silero VAD 활성화, condition_on_previous_text=true**로 검사한 원문이다.
모델 revision `d90ca5fe260221311c53c58e660288d3deb8d356`, 모델/VAD 파일 해시,
라이브러리 버전·전체 설정·각 입력 해시·반환 segment/info를 저장했다.
이전 실패 실행과 모든 decoder/VAD 인자가 같은지 스크립트가 대조한다.
**mall/market/cafe 각각 segment 0개, duration_after_vad=0.0, requiredEmptyPassed=true**다.
다른 다섯 WAV도 segment 0개다. threshold 조절이나 반환 segment 삭제는 하지 않았다.
테스트는 지정 시작점·true gate·VAD 설정·실제 WAV/manifest 해시와 아래 false 인수값을 함께 강제한다.
**humanListeningAcceptance=false, legalPrivacyClearance=false**를 유지한다.
Tiny-model ASR은 screening signal일 뿐이며 빈 결과는 말소리·음악·개인 대화가 없음을 증명하지 않는다.
출력 text/language도 환각일 수 있고 충실한 전사나 화자 식별로 주장하지 않는다.
독립적인 사람 청취 인증은 수행하지 않았다. 다만 제품 소유자 Oz는 2026-10-14 제공된
최종 WAV 8개 청취 검수 묶음과 명시된 자동 검사 한계를 기준으로 현재 자산 그대로 릴리스를
진행하도록 승인했다. 이 승인은 제3자의 법적/privacy clearance를 대신하지 않는다.
이전 market 60–72초/cafe 180–192초 실행은 market 3개/cafe 1개 segment를 반환하여
**requiredEmptyPassed=false**였으며 release acceptance 실패였다.
그 실행의 모든 screening 파일은 읽기 전용
[prior-attempt-market60-cafe180](../.agent/evidence-v0.2.3/privacy-screening/prior-attempt-market60-cafe180/)
아래 바이트 그대로 보존했다. [당시 final-asr.json](../.agent/evidence-v0.2.3/privacy-screening/prior-attempt-market60-cafe180/final-asr.json)을
성공으로 덮어쓰지 않았고 회귀 테스트가 이전 실패 상태와 모든 보존 파일 해시를 검사한다.
[기존 no-VAD 증거](../.agent/evidence-v0.2.3/privacy-screening/no-vad-asr.json)도 바이트 그대로 남겼다.
이 결과는 mall 36초/market 60초/cafe 180초에서 환각일 수 있는 candidate text를 냈으며,
새 market/cafe WAV의 검사 결과가 아니다. **no-VAD 결과는 지정된 VAD gate를 대체하거나 뒤집지 않는다.**
두 방법 모두 말소리/음악의 부재를 증명하지 않으며 사람의 청취 인수나 법적/privacy clearance를 제공하지 않는다.
Neo의 [이전 후보 scan](../.agent/evidence-v0.2.3/privacy-screening/candidate-scan-original.json),
[이전 파생본 ASR](../.agent/evidence-v0.2.3/privacy-screening/prior-derivatives-asr-original.json),
[당시 provenance](../.agent/evidence-v0.2.3/privacy-screening/earlier-asr-provenance.json)도 변경하지 않았다.
raw JSON에 없던 설정이나 입력 연결을 사후에 있었던 것으로 주장하지 않는다.
새 RED → GREEN, 전체 검증과 보존 기록은
[retry-market24-cafe0](../.agent/evidence-v0.2.3/privacy-screening/retry-market24-cafe0/),
현재 검증 요약은 [RESULT](../.agent/RESULT-v0.2.3.md)의 마지막 절에 있다.