Media — Transcription (STT) resilience — on-device-first
Contrato cross-surface para transcrição (speech-to-text) em apps Koder. Regra central: **on-device-first** — a transcrição DEVE funcionar offline e por padrão no próprio dispositivo (whisper/sherpa embarcado); o backend remoto (Koder AI Voice, `services/ai/voice`) é **enhancement opt-in** (mais acurácia/diarização/ áudio longo), nunca a dependência crítica. Privacidade-by-default: o áudio não sai do device sem confirmação. Gate de release via teste TTS→transcrever→assert (koder-stack#187). Realização de referência no Dek: dek#149 (local-first resilience) + dek#155 (fallback on-device).
Normative cross-surface. Onde um app Koder transcreve fala em texto (recorder, memo, legendas, interview capture), vale este contrato. Engine on-device via whispersherpa embarcado; engine remota = Koder AI Voice (`servicesai/voice
, self-hosted). Os dois são Koder — a decisão aqui é **resiliência + privacidade**, não Koder-vs-externo (esse é oself-hosted-first.kmd`, já satisfeito).
1 — MUST: on-device-first (o piso)
- R1 — Default on-device. A transcrição DEVE rodar *o próprio dispositivo por
padrão e funcionar offline* Abrir uma gravação e transcrever NÃO PODE depender de rede nem de um backend alcançável.
- R2 — Remoto é enhancement opt-in. O Koder AI Voice remoto só entra quando o
usuário opta (mais acurácia, diarização, sumarização, áudio longo) e há rede. Nunca é o caminho crítico; sua indisponibilidade não quebra a transcrição.
- R3 — Degradação graciosa. Backend remoto gated401403offlinetimeout →
cair pro on-device com aviso inline claro ("Sem conexão — transcrevendo neste dispositivo"), NUNCA uma tela de erro terminal. (Antipadrão observado:
DEK-AUT-003/DEK-NET-001viravam "Falha na transcrição" sem fallback efetivo.)
2 — MUST: privacidade-by-default
- Transcrever on-device mantém o áudio no device — alinha com
audio.kmd §3("NUNCA auto-upload sem confirmação"). Enviar o áudio pro backend remoto exige o opt-in da R2 (consentimento), não pode ser silencioso.
- O modelo on-device e seus assets ficam embarcados/baixados localmente; nenhum
conteúdo (transcrição, áudio, hash) vaza em telemetria (
voice/wake-word.kmd §obs).
3 — MUST: empacotamento do engine on-device
- A lib nativa de STT embarcada (ex.:
libwhisper.so) DEVE respeitar os gates deempacotamento da plataforma — em Android, 16 KB page-alignment (
-Wl,-z, max-page-size=16384), senão o gate strict de release reprova (dek#137/#155). - Modelo embarcadobaixável versionado via model catalogregistry (dek#149 + modelreg).
4 — MUST: teste de corretude (gate de release)
Todo componente com transcrição DEVE ter o TDD gerado pela categoria transcription do /k-test (koder-stack#187): TTS sintetiza uma frase canônica conhecida em N idiomas (piper) → roda pela função de transcrição (on-device E, se configurado, remoto) → assert fuzzy (contains/WER ≥ limiar) por idioma. Reprova a release se a transcrição (no piso on-device) não devolver o texto esperado — teria pego o backend gated antes de publicar.
5 — Adoption checklist (per app)
- [ ] Transcrição funciona offline (R1) — testar com rede desligada.
- [ ] Remoto é opt-in (R2); sua falha cai pro on-device com aviso (R3).
- [ ] Áudio não sai do device sem consentimento (privacidade §2).
- [ ] Lib STT nativa 16 KB-aligned (§3) — passa o gate de release Android.
- [ ] TDD
transcription(koder-stack#187) no gate de release.
Non-normative — referências
- Realização de referência: Dek —
dek#149(local-first resilience + modelcatalog),
dek#150(connectivity-aware + fallback local + aviso inline, DONE),dek#155(fallback on-device),dek#137(16 KB gate). - Engine remota:
services/ai/voice(Koder AI Voice). Engine on-device:whisper/sherpa via
whisper_ggml_plus. - Teste:
koder-stack#187. Privacidade:audio.kmd §3. Resiliência:always-on.kmd.