Media — Transcription (STT) resilience — on-device-first

mandatory

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 é o self-hosted-first.kmd`, já satisfeito).


1 — MUST: on-device-first (o piso)

  1. 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.

  2. 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.

  3. 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-001 viravam "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 de

    empacotamento 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: Dekdek#149 (local-first resilience + model

    catalog), 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.