Files
luke_scribe/.omc/plans/consensus-luke-scribe-stt-api.md
T
lukehemmin 84faa121fe docs: resolve open questions, recompute ambiguity ~10%→~5% (v2.3)
Fold post-plan decisions into the spec and consensus plan:
- Q1 deploy HW: undecided/mixed → delegate to hardware-adaptive auto-sizing
- Q2 model strategy: collapse to single turbo model if P1 bench entity ≥95%
- Q3 cancellation: cooperative (segment-boundary) is sufficient; no hard-kill
- Q4 concurrency N: delegate to boot-time auto-sizing (AC-8 = ≤5s within auto N)

Recompute clarity with the deep-interview model (Goal 0.96 / Constraint 0.95
/ Success 0.95 → Total 0.954): ambiguity ~10% → ~5%. Residual is now entirely
measurement/code-gated (AC-4 R-WER baseline, hybrid→single confirmation,
CT2 GIL) — next lever is P1 bench, not further interview.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 11:07:36 +09:00

28 KiB
Raw Blame History

Consensus Implementation Plan: luke_scribe — 로컬 STT 전사 API

  • Status: pending approval (consensus v2.3 — v2.2 + §11 Open Q 후속확정·모호도 ~5% 재산출(2026-06-07); v2.1 합의 + CCG 외부리뷰(Codex/Gemini) 반영; §3.6 능력등급·§3.10 프로비저닝/WS/공유스토어/Colab)
  • Mode: --consensus --direct --deliberate
  • Source spec: .omc/specs/deep-interview-luke-scribe-stt-api.md (ambiguity ~10%, PASSED)
  • Project: greenfield /root/luke_scribe
  • Generated: 2026-06-02 · Revised: 2026-06-02 (v2)

v2 changelog는 문서 맨 끝 §13 참조. v1 대비 P0 3건(워커 실행모델, VRAM 측정/단계역전, 취소·임시파일·보관경합), P1 4건, P2 3건, 모호 AC 4건을 반영.


1. Requirements Summary

내부용(비공개) 로컬 STT 전사 API. 단일 Job 추상화로 배치(파일/영상)실시간(WebSocket) 입력 처리. faster-whisper(CTranslate2) 런타임, 하이브리드 모델(실시간=turbo, 배치=large-v3) — 단 P1 bench 게이트로 검증. Device Manager 가 GPU/CPU를 감지하고 부팅 시 VRAM 실측으로 정밀도·워커수를 산정(1050~H100), auto|cpu|cuda 강제 가능. Redis(RQ) 영속 큐(배치) + 전용 실시간 핸들러(WS), queue_position·progress 보고. 요청별 출력옵션(txt/ts/word/diarize/SRT/VTT). 후처리(glossary→rules→LLM(local/external, 기본 off·신뢰도 게이팅)→confidence). API Key 인증(+스코프), 결과 7일 보관·파생 오디오 포함 즉시 삭제, 4h/2GB → 413, 큐 만재 → 429. 배포: CLI(dev/Colab)+Docker(prod)+Colab cloudflared. diarization 옵션(pyannote).


2. RALPLAN-DR Summary

Principles

  1. Hardware-adaptive, fail-explicit — 1050~H100 자동 감지·정밀도/동시성 산정. 적재 불가 시 모델/정밀도 강등 → CPU로 우아하게 내려가되, 강등이 불가능하면 명확한 오류로 거부(조용한 OOM·무한 강등 금지). "never fail"이 아니라 "never fail silently".
  2. One Job abstraction, two execution lanes — 모든 입력을 Job 수명주기(queued→processing→completed/failed/cancelled)로 통일하되, 배치=RQ 워커 / 실시간=장수명 WS 핸들러로 실행 레인을 분리(WS는 enqueue-once가 아니므로).
  3. Accuracy/latency 분리(검증 기반) — batch=large-v3, realtime=turbo. 단 하이브리드 채택은 P1 bench의 측정 델타로 게이트(불충분하면 단일 모델로 단순화).
  4. Privacy-first, enforced — 원본+파생 오디오 즉시 삭제(모든 종료 경로 finally), 결과 7d TTL, 외부 LLM egress는 allowlist+opt-in+감사로그 없이는 금지.
  5. Dev/prod parity — 동일 코어, CLI(dev/Colab)/Docker(prod)는 설정 차이. 큐는 prod=RQ / dev=in-proc 폴백이되 동일 Job 인터페이스 뒤에 두어 의미 동등성 유지.

Decision Drivers (top 3)

  1. 혼용어(KO+EN) 정확도 — hotwords + 모델 선택 + 후처리.
  2. 하드웨어 이식성 + 자동 스케일(실측 기반).
  3. 동시성 + 가시성(queue_position/progress).

Viable Options

D1. 큐/동시성 백엔드

  • (A) Redis + RQ SimpleWorker(no-fork) + 장수명 모델 보유 프로세스 (채택, 사용자 Redis 확정 + fork 문제 회피) — Pros: 영속·재시작 내성, 모델 1회 적재 후 재사용, CUDA-fork 충돌 회피. Cons: SimpleWorker는 작업 중 하트비트 없음 → progress emit로 보완 필요.
  • (B) Redis + Celery — Pros: 라우팅/우선순위/재시도 성숙. Cons: GPU 단일박스엔 과함. Invalidation: RQ+SimpleWorker로 충분.
  • (C) in-process asyncio + GPU 세마포어 — dev/단발 폴백 + P2 컨틴전시(RQ/CUDA가 막히면 동일 Job 인터페이스로 폴백).

⚠️ 근거: RQ 기본 워커는 작업당 os.fork()하며, 부모에서 초기화된 CUDA 컨텍스트는 fork된 자식에서 재사용 불가(pytorch#40403). 따라서 fork 금지(SimpleWorker/장수명) 가 필수. RQ progress는 내장이 없어 job.save_meta() 수동 호출 필요(RQ docs).

D2. 실시간 스트리밍 구현

  • (A) faster-whisper 위 커스텀 LocalAgreement-2 (채택) — Pros: 큐/디바이스/후처리 통합 제어. Cons: 안정화 정확성 직접 구현(난이도 과소평가 금지 → §3.7c 계약 명시). 지연 3~5초 관대는 지연만 완화하지 정확성은 아님.
  • (B) WhisperLive 백엔드 vendoring — 검증된 WS+VAD를 backend로 감싸기. Invalidation: 통합·하이브리드 제어가 우선이나 청킹/안정화 휴리스틱은 차용.
  • (C) WhisperLiveKit(AlignAtt/SimulStreaming) — 2025 SOTA. Invalidation: 3~5초 목표엔 과투자(P5 옵션).

D3. 추론 백엔드 추상화

  • (A) faster-whisper 단일 엔진 + compute_type 자동 — Pros: GPU/CPU/int8/fp16 단일 경로. Cons: 타 엔진 미지원(범위상 불필요).
  • (B) 멀티 엔진 플러그인Invalidation: 조기 추상화 → 얇은 인터페이스(engine/base.py)만 두고 구현 1종.

3. Target Project Structure

luke_scribe/
├── pyproject.toml (uv; extras: gpu, diarize, llm)   ├── run.sh   ├── .env.example
├── docker/{Dockerfile.gpu, Dockerfile.cpu, docker-compose.yml}
└── src/luke_scribe/
    ├── config.py        # pydantic-settings (model rt/batch, device, precision, redis, retention, api_keys+scopes, tunnel, corrector+allowlist)
    ├── cli.py           # typer: serve | transcribe | bench | detect
    ├── api/{app.py, deps.py, schemas.py, routes/{jobs.py, stream.py, admin.py}}
    ├── devices/{manager.py, profile.py, vram_probe.py}
    ├── engine/{base.py, faster_whisper_engine.py, model_registry.py}
    ├── audio/{ingest.py, vad.py}
    ├── pipeline/{batch.py, realtime.py}
    ├── jobqueue/{broker.py, jobs.py, worker.py, inproc.py, cancel.py}
    ├── postprocess/{pipeline.py, glossary.py, rules.py, llm.py, confidence.py}
    ├── diarization/pyannote_diarizer.py
    ├── results/{store.py, formats.py, retention.py}
    ├── connectivity/tunnel.py
    └── observability/{logging.py, metrics.py}

3.5 Worker Execution Model & GPU Concurrency (P0-1 해소)

  • 배치 레인: RQ SimpleWorker(또는 장수명 커스텀 워커). 워커 부팅 시 WhisperModel1회 적재해 프로세스 수명 동안 보유(재적재·fork 금지). GPU당 워커 프로세스 1개 기본, 워커 내 GPU 접근은 단일 스레드(동시 decode 금지). 동시성 = device-bound 워커 프로세스 수(인터프로세스), --workers 오버라이드.
  • 실시간 레인: WS 세션은 enqueue-once가 아니므로 RQ에 넣지 않고 API 프로세스 내 장수명 turbo 핸들러(asyncio + 단일 GPU 락)가 처리. 세션→Job 매핑은 상태 추적용으로만.
  • 하트비트/heartbeat 공백 보완: SimpleWorker는 작업 중 하트비트가 없으므로 §3.7d의 throttled progress emit가 사실상 하트비트 역할(장시간 작업이 "멈춤"으로 오인되지 않게).
  • 컨틴전시/Colab: GPU·RQ가 막히거나 Colab(Docker 불가) 이면 D1-C in-proc 큐(Redis 불필요) 로, 동일 Job 인터페이스 유지(§3.10d).

3.6 VRAM Sizing & Capability Tier (P0-2 해소 + CCG ③: 능력 등급 자동판정)

  • 부팅 시 실측(devices/vram_probe.py): GPU VRAM(총/여유)·RAM·디스크 여유 감지 + 대상 모델을 1회 로드해 allocated 실측(헤드룸 ×1.3). 정적 상수 비의존.

  • 보수 기본 상수(측정 전 폴백): large-v3 fp16 ≈10GB·int8 ≈3.5GB, turbo fp16 ≈4GB·int8 ≈1.8GB.

  • 능력 등급(자동 — 무음 모델강등이 아니라 "제공 가능 모델"을 등급이 결정):

    등급 조건(실측) 제공
    T0 CPU GPU로 turbo도 무리/GPU 없음 turbo@CPU
    T1 turbo-GPU turbo는 GPU OK, large-v3 무리 turbo@GPU (large-v3 미제공 → 배치도 turbo)
    T2 스왑 large-v3 OK, turbo와 동시상주 불가 호출별 load/unload(MRU 상주, 스왑 최소화)
    T3 동시상주 turbo+large-v3 동시 적재 가능 둘 다 상주 → rt(turbo)+batch(large-v3) 동시
    T4 모델 다중복제 제외
  • 정밀도: cc≥7.0&free≥12GB→float16; cc≥7.0&free<12GB→int8_float16; Pascal(6.x)→int8; CPU→int8.

  • 워커수: workers = max(1, floor((free_VRAM reserve) / measured_per_worker)) (§3.9b의 reserve = 헤드룸 + 실시간 모델 footprint).

  • 디스크 가드: 다운로드 전 여유 공간 확인, 부족 시 명확 오류.

  • 투명성: /v1/system·/v1/models로 등급·제공모델, 결과에 model_used/compute_type_used 항상.

  • OOM 처리: 강등 시도 ≤2회(fp16→int8→CPU) 후 실패(재큐 1회). 1050: T1(turbo-int8)/T0. T4~H100: T3.

3.7 Job Lifecycle: Cancellation, Temp Files, Retention (P0-3 해소)

  • (a) 협조적 취소: DELETE /v1/jobs/{id} → Redis에 cancel 플래그. 워커는 faster-whisper 세그먼트 제너레이터를 소비하며 세그먼트 경계마다 플래그 확인(유일한 선점 지점). 현재 세그먼트 연산은 완료 후 중단 → 상태 cancelled. (긴급 hard-kill은 워커 프로세스 종료 옵션으로만.)
  • (b) 임시파일 수명: ffmpeg 파생 wav는 추적 tempdir에 생성, 모든 종료 경로(success/fail/cancel/OOM)의 finally에서 삭제. 업로드 원본도 전사 시작 시점 이후 보유하다 종료 시 삭제.
  • (c) 실시간 LocalAgreement 계약: 설정 명시 — redecode_window(예: 마지막 15s 오디오), confirmed_prefix 절단 규칙, retained_left_context(예: 5s), VAD 무음 경계에서 확정. 확정 세그먼트 방출 후 버퍼 절단(메모리 평탄). 단위 테스트로 버퍼 절단 불변식 검증.
  • (d) progress 발행: 워커가 제너레이터를 소비하며 processed_sec/total_sec 계산 → throttled job.save_meta()(N 세그먼트마다 또는 ≥1s). total_sec는 ingest 시 duration probe로 확보. queue_position = 레인 큐 인덱스.
  • (e) 보관 sweeper 경합: results/retention.py터미널 상태(completed/failed/cancelled) Job만 7d TTL 청소. {queued, processing} 보유 결과·임시물은 건드리지 않음.

3.8 Security Boundary (P1-7 해소)

  • API Key + 스코프: X-API-Key 검증 + ApiKey.scopes 강제(예: transcribe, admin). 키 회전/폐기 설정.
  • 외부 egress 통제: LLM external/openai 백엔드는 config allowlist 엔드포인트에만 송신 가능(SSRF 방지), 기본 off + 명시 opt-in + 전송 1건당 감사 로그(key id, endpoint, job id). 옵션으로 전송 전 PII 마스킹.

3.9 Shared-GPU Accounting & Realtime Concurrency (v2.1 — 합의 잔여조건)

  • (a) 이벤트 루프 비블로킹: 실시간 turbo decode는 동기 CTranslate2 호출이므로 await loop.run_in_executor(single_thread_executor, decode) 로 오프로딩(단일 GPU 락 직렬성 유지). P3 착수 시 CT2의 GIL 해제 여부 검증 — 미해제면 실시간 레인을 별도 디코드 프로세스로 분리. (NEW-1a)
  • (b) 공유 GPU VRAM 회계: reserve = base_headroom + (realtime_enabled ? measured_realtime_vram : 0). 실시간 모델이 동일 GPU 상주 시 배치 워커수 공식(§3.6)이 그 footprint를 반드시 포함 → 단일 GPU + 실시간 동시 활성에서 oversubscribe 금지. (NEW-1b)
  • (c) 실시간 동시 세션: turbo 인스턴스 1개를 전 세션이 직렬 공유(단일 GPU 락). 최대 동시 WS 세션 상한(설정) + 초과 시 거부/대기, 실시간 레인 대기시간 메트릭. AC-8(≤5s)은 "≤N 세션 한도 내" 보장으로 명시. (R3)
  • (d) 실효 compute_type 로깅: vram_probe//v1/system요청 vs 실효 compute_type 보고, 불일치(T4 int8_float16 무음 강등 등) 경고. AC-2/3 계약에 포함. (NEW-2/R2)
  • (e) RQ job_timeout: enqueue 시 job_timeout ≥ 4h(+마진)(duration probe 기반). RQ 기본 180s로는 장시간 작업이 3분에 강제 종료되어 AC-7 위반 → 반드시 상향. (R1/NEW-3)
  • (f) Phase Exit 구속력: 각 Phase Exit는 hard gate(미충족 시 다음 Phase 착수 금지). 단 옵션 기능(diarization/LLM/tunnel) 미완은 "문서화된 제한"으로 soft 허용. (R4)

3.10 CCG 리뷰 반영 — 프로비저닝·WS·공유스토어·실행 프로파일 (v2.2)

  • (a) 모델 프로비저닝(오프라인 강제 폐기): 시작 시 모델 존재 확인 → 없으면 HF 다운로드(인터넷 OK) → 체크섬/로드 실패 시 캐시 purge 후 1회 재다운로드 → 준비 전 API는 503/status:"loading". ("로컬 실행"=외부 STT API 미사용이지 에어갭 아님 — 스펙 "오프라인" 문구 폐기.)
  • (b) WS init-frame 인증: 연결 직후 첫 메시지 {type:"init", api_key, audio:{codec,sample_rate,channels}, options}, 2초 내 미수신 시 close. 헤더 못 쓰는 브라우저 대응 + 키가 URL/로그에 안 남음. 코덱/샘플레이트도 이 프레임에서 협상(Gemini WS 지적 흡수).
  • (c) 공유 스토어(#1, 프로덕션 Docker 한정): api↔worker가 별도 컨테이너 → 입력 원본·파생 wav·결과를 공유 볼륨/오브젝트 스토어, Job 메타는 Redis. per-container 로컬 SQLite 금지. Colab/단일프로세스는 디스크 1개라 무관.
  • (d) 실행 프로파일 2종(코드 동일): Colab/개발=순수 Python(run.sh/python -m ...in-proc 큐(Redis 불필요)·로컬 디스크·cloudflared 바이너리. 프로덕션=Docker+Redis+worker+공유 스토어. (Colab은 Docker 불가가 하드 제약.)
  • (e) 언어/hotwords: 기본 language="ko"(요청별 override). hotwords는 선택(반복 고정용어 1회 등록; 매 전사 예측 아님) — 기본 경로는 ko 앵커+모델+rules 후처리, P1 bench로 hotwords 불필요 여부 실측.
  • (미채택·추후: webhook, Idempotency-Key, 페이지네이션, 만료 410.)

4. Implementation Steps (by phase, with file refs & exit criteria)

P1 — Core + 측정 게이트

  1. 스캐폴딩pyproject.toml(extras), config.py, run.sh.
  2. Device Manager + VRAM probedevices/{manager.py, vram_probe.py, profile.py}: 감지 + §3.6 실측·정밀도·워커수·Model-Fit 분기. AC-2/3.
  3. Engine + registryengine/faster_whisper_engine.py(transcribe: hotwords/initial_prompt/word_ts/vad), model_registry.py(rt=turbo/batch=large-v3, 오버라이드). AC-4.
  4. Audio ingest(스트리밍)audio/ingest.py: ffmpeg를 파일로 파이프(전체 배열 인메모리 금지), duration/size probe, 4h/2GB→413. audio/vad.py: Silero VAD. AC-7/9.
  5. CLI detect/transcribe/benchbenchP1로 전진: 도메인 KO+EN 클립으로 turbo vs large-v3 R-WER + entity 보존율 + 속도 + 실측 VRAM 측정 → 하이브리드 게이트 판정. AC-4/12.
  • Exit: CPU와 실 GPU 1종에서 단일 파일 전사 성공; detect가 measured VRAM·정밀도·워커수 출력; bench가 모델 델타 리포트 산출.

P2 — API + Queue

  1. FastAPI + 인증api/{app.py, deps.py, schemas.py}: API Key+스코프(§3.8). AC-11.
  2. RQ 워커(SimpleWorker)jobqueue/{broker.py, jobs.py, worker.py, cancel.py, inproc.py}: §3.5 실행모델, §3.7d progress, §3.7a 취소, §3.6 OOM 강등. AC-5/6.
  3. Jobs 라우트api/routes/jobs.py: POST /v1/jobs(만재→429), GET(queue_position/progress), result?format=, DELETE(취소), GET /v1/jobs. AC-1/6.
  4. Results + retentionresults/{store.py, formats.py, retention.py}: §3.7b/e, 원본·파생 삭제, 7d TTL 터미널만. AC-11.
  5. DockerDockerfile.{gpu,cpu} + compose(api+redis+worker). CT2/CUDA/cuDNN 트리플 핀(예: CUDA12+cuDNN9; 구형/Colab은 CT2 다운그레이드 경로 문서화). detect가 런타임 CUDA 버전 노출. AC-12.
  6. Admin/health, /v1/system(profile/워커/큐깊이/가용 VRAM), /v1/models.
  • Exit: 다건 enqueue→progress→result; 강제 OOM 시 강등·실패 경로 시연; 취소가 cancelled로 종료 + 임시파일 삭제 확인.

P3 — Realtime

  1. 실시간pipeline/realtime.py(§3.7c 계약: redecode_window/prefix/left-context/VAD), api/routes/stream.py(WS, partial/final/status, 백프레셔). AC-8.
  • Exit: 부분결과 ≤5s + 최종 안정화; 30분 세션 메모리 평탄(±15% 이내, 단조증가 없음).

P4 — Output + Post-processing

  1. 출력 옵션 — timestamps/word/SRT/VTT 요청별. AC-9.
  2. 후처리(glossary/rules/flag)postprocess/{pipeline.py, glossary.py, rules.py, confidence.py}. AC-10.
  • Exit: glossary on/off diff로 entity 보존 향상 측정; 저신뢰 플래그 부착.

P5 — Advanced

  1. LLM 보정(옵션)postprocess/llm.py: local/external 백엔드, §3.8 egress 통제, confidence-gated, 기본 off. AC-10.
  2. Diarization(옵션)diarization/pyannote_diarizer.py(HF 토큰).
  3. Colab 터널connectivity/tunnel.py: API lifespan에 종속 supervise(같이 start/stop), URL 회전 시 재출력, 임시성 명시. AC-13.
  4. 관측/벤치 확장observability/{logging,metrics}.py(큐깊이·워커가동·RTF·OOM 카운트), bench 확장.
  • Exit: external egress allowlist+감사로그 동작; Colab serve --tunnel cloudflare 외부 200.

5. Acceptance Criteria (수치화)

스펙 AC-1~13 상속 + 모호 항목 절대 기준화:

  • AC-2/3: detect가 measured VRAM 기반 정밀도/워커수 산정 + 능력 등급(T0~T3) 자동판정·/v1/models 제공모델·model_used 표시(§3.6); 1050→int8/CPU(large-v3 GPU 불가), T4→int8_float16, A100/H100→fp16.
  • AC-4(혼용어, 절대): 도메인 entity 용어(vLLM·API·FastAPI·Kubernetes·LLM·GPU 등) verbatim 보존율 ≥ 95%(hotwords on, domain set), 그리고 도메인 R-WER ≤ {P1 bench 기준선}. 보조로 batch(v3) ≤ realtime(turbo).
  • AC-5/6: 다건 동시 → 각 GETqueue_position(앞 N건)·progress %(processed_sec/total_sec); 만재 429.
  • AC-7(메모리, 절대): 2h 배치 + 30분 WS에서 워밍업 후 peak RSS 변동 ±15% 이내, 단조 증가 없음; OOM 없음; 4h/2GB→413.
  • AC-8: 부분결과 ≤5s(동시 ≤N 세션 한도 내), 최종 안정화; 다중 세션 부하에서도 REST/배치 응답성 유지(이벤트 루프 비블로킹, §3.9a).
  • AC-11: 전사 후 원본+파생 wav 부재; 결과 7d 후 만료; 터미널 Job만 청소.

6. Risks and Mitigations

Risk Mitigation
CUDA fork 실패 SimpleWorker/장수명·model-load-once, fork 금지(§3.5)
OOM(동시성) 측정 VRAM(§3.6) 기반 워커수, semaphore, 강등 최대 2회 후 실패
turbo 혼용어 부족 P1 bench 게이트(§4-5), 하이브리드/hotwords/후처리, 모델 스왑
실시간 떨림/누수 LocalAgreement 계약(§3.7c), 버퍼 절단 불변식 테스트
취소 no-op / 임시파일 누출 협조적 취소 + finally 삭제(§3.7a/b)
보관 경합 터미널 상태만 sweeper(§3.7e)
외부 LLM PII 유출 allowlist+opt-in+감사로그+마스킹(§3.8)
CT2/cuDNN 버전 불일치 Dockerfile 트리플 핀 + 다운그레이드 경로(P2-10)
Redis SPOF in-proc 폴백(D1-C), 헬스체크

7. Pre-mortem (deliberate — 3 시나리오, 위험표와 비중복)

  1. "P2 통합에서 워커가 fork-CUDA로 즉시 죽었다." 원인: RQ 기본 fork. 예방: §3.5 SimpleWorker 강제 + P2 Exit에 "실 GPU 워커 기동" 게이트, P1에서 워커 기동 스파이크 선검증.
  2. "데모에서 'vLLM'→'브이엘엘엠'으로 신뢰 상실." 원인: 모델/hotwords 미검증. 예방: P1 bench 게이트(entity 보존율 ≥95% 기준), 기본 hotwords 사전 동봉, 미달 시 v3 채택 자동 판정.
  3. "30분 WS 세션에서 메모리 누수로 컨테이너 OOM-kill." 원인: 링버퍼/가설 미절단. 예방: §3.7c 절단 계약 + 버퍼 불변식 단위테스트 + P3 Exit의 ±15% 메모리 게이트.

8. Expanded Test Plan (deliberate, 수치 게이트 포함)

  • Unit: Device 결정(cc/measured-VRAM→compute_type/workers/Model-Fit 분기), OOM 강등 캡(≤2), LocalAgreement 버퍼 절단 불변식, formats(srt/vtt 타임코드), rules 정규화, retention(터미널만), options(413/429).
  • Integration: ffmpeg(스트리밍, 인메모리 아님)→engine→result, Redis enqueue→SimpleWorker→progress(save_meta throttle)→status, 취소 플래그→cancelled+임시파일 삭제, glossary diff(entity 보존율), egress allowlist 차단/허용.
  • E2E: 파일 Job 수명주기(생성→progress→결과·원본+파생 삭제), 동시 다건 queue_position, WS 세션(부분≤5s), Colab serve --tunnel cloudflare 200, 강제 OOM 강등 경로.
  • Observability: 메트릭(큐깊이·워커가동률·RTF·OOM 카운트·실시간 레인 대기시간), 구조적 로그(job_id 상관), /health·/v1/system 계약(요청 vs 실효 compute_type 보고 검증), 2h 배치/30분 WS RSS ±15% 평탄 검증, external egress 감사로그 1건/전송, 다중 세션 AC-8(≤5s) + 동시 GET /v1/jobs 응답성 바운드, >180s 작업이 job_timeout으로 강제종료되지 않음, 공유 GPU(배치+실시간) VRAM 비-oversubscribe Model-Fit 상호작용 테스트.

9. Verification Steps

  1. uv sync && uv run python -m luke_scribe.cli detect → measured VRAM·정밀도·워커수.
  2. ... bench --samples samples/ko_en/ → turbo vs v3 R-WER·entity 보존율·VRAM → 하이브리드 판정.
  3. ... transcribe samples/ko_en.wav → entity verbatim ≥95% 확인.
  4. docker compose up → 다건 POST/GET(progress/위치), 결과 후 원본+파생 부재, DELETEcancelled.
  5. 강제 작은-VRAM 환경 → 강등(≤2)·실패 경로 시연.
  6. WS 클라이언트 30분 → 부분≤5s, RSS ±15%.
  7. pytest tests/(unit/integration) + e2e 스모크.
  8. Colab → serve --tunnel cloudflare URL 외부 200; egress allowlist 차단 테스트.

10. ADR (refined)

  • Decision: faster-whisper 단일 엔진 + (게이트된)하이브리드 모델 + Redis(RQ SimpleWorker, no-fork, model-load-once) 배치 + 전용 WS 실시간 핸들러 + 측정 기반 DeviceProfile + CLI/Docker(버전 핀).
  • Drivers: 혼용어 정확도, 이식성/자동스케일(실측), 동시성/가시성.
  • Alternatives: Celery(과함), in-proc(폴백/컨틴전시), WhisperLive/Kit(참고/P5), 멀티엔진(조기), RQ 기본 fork(CUDA 불가→거부).
  • Why chosen: 사용자 확정(하이브리드/Redis/후처리/보관/상한/diarize) 준수 + fork/VRAM/취소 리스크를 명시 메커니즘으로 해소.
  • Consequences: SimpleWorker 하트비트 공백→progress로 보완; 실시간 안정화 자체 구현; 1050 배치 large-v3 GPU 불가; Redis 의존; 공유 GPU에서 배치+실시간 VRAM 합산 회계(§3.9b)·실시간 decode 오프로딩(§3.9a) 필요.
  • Follow-ups: Redis HA, SimulStreaming(P5), egress 마스킹 고도화. (도메인 bench는 follow-up이 아니라 P1 게이트로 승격.)

11. Open Questions → 후속 결정 반영 (RESOLVED · 2026-06-07)

  1. 배포 타깃 HW: 미정/혼합으로 확정 → 단일 타깃을 고정하지 않고 §3.6 하드웨어 적응형 자동산정에 위임. 워커수 공식·공유스토어는 부팅 실측으로 런타임 결정(설계 원칙 #1과 합치). (잔여 검증: 특정 배포는 P1 detect/bench로.)
  2. 모델 전략 규칙(확정): P1 bench에서 turbo의 entity 보존율 ≥95%(+R-WER ≤ 기준선)이면 배치도 turbo 단일모델로 통일(기본 지향=단순화, VRAM·복잡도 절감, T2 스왑 회피). 미달 시에만 하이브리드(batch=large-v3) 유지. → 아키텍처 분기를 측정 기반 결정규칙으로 확정(분기 모호 제거).
  3. 취소 의미론(확정): 협조적 취소(세그먼트 경계)로 충분. hard-kill 경로 비채택(필요 시 follow-up). §3.7a 그대로.
  4. 동시성 상한 N(확정): 자동산정 위임 → AC-8의 N은 부팅 시 하드웨어 기반 자동 산정(고정 목표 없음). AC-8 = "≤5s within auto-sized N".

12. v2 Changelog (적용 내역 → 리뷰 매핑)

  • [P0-1] §3.5 Worker Execution Model 신설 — SimpleWorker/no-fork/model-load-once, 배치·실시간 레인 분리, in-proc 컨틴전시. (Arch P0-1, Critic F1)
  • [P0-2] §3.6 VRAM 부팅 실측 + 보수 상수(large-v3 fp16 10GB) + Model-Fit 분기 + benchP1로 전진(단계 역전 수정). (Arch P0-2/P1-4, Critic F2)
  • [P0-3] §3.7 협조적 취소 + 임시파일 finally 삭제 + 보관 sweeper 터미널-한정. (Arch P0-3/P1-6, Critic F3)
  • [P1] §3.7d progress 메커니즘(save_meta throttle), §3.8 보안 egress allowlist+감사+스코프, 하이브리드 P1 게이트. (Arch P1-4/5/7, Critic F4/F5)
  • [P1-신규] §4 단계별 Exit Criteria + in-proc 컨틴전시 명시. (Critic F6)
  • [P2] §3.7c LocalAgreement 계약, §4-4 ffmpeg 스트리밍 보장, §4-10/17 cloudflared lifecycle + CT2/CUDA/cuDNN 핀. (Arch P2-8/9/10)
  • [AC] AC-4 절대 기준(entity 보존율 ≥95% + R-WER 기준선), AC-7 메모리 ±15% 평탄, 워커당_추정=측정값, OOM 강등 ≤2회, 429/413 분리. (Critic 모호성 4건)
  • [Risk] OOM 위험을 측정 상수 기반으로 재작성(순환성 제거); pre-mortem #1을 위험표와 비중복화하고 예방을 P1/P2 게이트에 배선.

13. v2.1 Changelog (합의 잔여조건 반영)

  • [NEW-1a] §3.9a 실시간 decode run_in_executor 오프로딩(+GIL 검증/프로세스 분리 폴백).
  • [NEW-1b] §3.9b reserve에 실시간 모델 VRAM 포함 → 공유 GPU oversubscribe 방지.
  • [R1/NEW-3] §3.9e RQ job_timeout ≥ 4h.
  • [NEW-2/R2] §3.9d 요청 vs 실효 compute_type 로깅 + AC-2/3 계약 + 관측 테스트.
  • [R3] §3.9c 실시간 최대 동시 세션 상한 + 대기시간 메트릭 + 다중세션 AC-8 테스트.
  • [R4] §3.9f Phase Exit 구속력(hard/soft) 명시.

합의 결과 (Consensus Outcome)

  • Architect (v2): APPROVE WITH CONDITIONS — P0×3 해소 확인, 잔여 NEW-1(a/b)/2/3.
  • Critic (v2): APPROVE WITH CONDITIONS — CRITICAL×3·MAJOR×3 해소 확인, NEW-1 검증 + R1~R4.
  • 모든 잔여 조건을 v2.1에 반영 → 합의 도달. iteration 2/5.

14. v2.2 Changelog — CCG 외부 리뷰(Codex/Gemini) 반영

  • ②→프로비저닝: "오프라인 강제" 폐기. 다운로드 OK + 손상 재다운로드 + loading 상태(§3.10a). 스펙 제약 문구 수정.
  • ③→능력 등급: §3.6을 T0(CPU)~T3(동시상주) 자동판정으로 재작성, T4(다중복제) 제외, model_used 항상 표시(무음 모델강등 폐기).
  • ④→WS init 인증: §3.10b 첫 메시지 인증+코덱 협상. hotwords는 선택으로 강등(§3.10e).
  • ⑤→기본 ko: 요청별 override(§3.10e).
  • #1→공유 스토어: 프로덕션 Docker 한정 공유 볼륨/오브젝트 스토어(§3.10c); Colab 무관.
  • Colab: Docker 불가 → 순수 Python·in-proc·바이너리 cloudflared(§3.5, §3.10d).
  • 출처: .omc/artifacts/ask/{codex,gemini}-20260603-095739.md. 미채택(추후): webhook·Idempotency-Key·페이지네이션·410.

15. v2.3 Changelog — 후속 결정 반영 + 모호도 재산출 (2026-06-07)

  • Open Q1~Q4 확정(§11): 배포HW=적응형 위임(미정/혼합), 모델=단일통일 규칙(P1 bench 게이트), 취소=협조적, 동시성 N=자동산정 위임.
  • 모호도 재산출(딥인터뷰 모델 종합): ~10%(인터뷰) → ~6%(계획 v2.2) → ~5%(후속 결정). Goal 0.96×0.40 + Constraint 0.95×0.30 + Success 0.95×0.30 = Total Clarity ≈0.954 → Ambiguity ≈0.046.
  • 잔여 모호(전부 측정·코드 시점에만 닫히는 known-unknown): ① AC-4 R-WER 기준선(P1 bench), ② 하이브리드→단일 최종 확정(P1 bench 결과), ③ CT2 GIL→실시간 프로세스 분리(P3). 대화 레버 소진 → 다음 레버는 P1 bench 실행.

Consensus v2.3 — pending approval. 실행(team/ralph/autopilot)은 사용자의 별도 명시 승인이 있어야만 진행됩니다. 승인 전 소스 수정·커밋·실행 스킬 호출 없음.