playbook/antigravity-awesome-skills/skills/matematico-tao/references/auri-analysis.md

7.0 KiB
Raw Blame History

Auri/EarLLM — Contexto Completo para Análise Matemática

Visão Geral do Sistema

Projeto: Auri v2.5.0 (EarLLM One) Localização: C:\Users\renat\earbudllm Tipo: Android app multi-módulo (Kotlin + Jetpack Compose) Função: Pipeline de voz → STT → LLM → TTS via Bluetooth earbuds


Arquitetura de Módulos

app (orquestrador)
├── core-logging (cross-cutting: logging, métricas)
├── bluetooth (conectividade BT — A2DP, HFP, SCO)
├── audio (captura PCM, roteamento, botões hardware)
├── voice (STT, TTS, pipeline de voz)
├── llm (clients: OpenAI, Claude, Gemini, Ollama, RPA)
└── integrations (Gmail OAuth2)

Grafo de Dependências (formal)

G = (V, E) onde:
V = {app, bluetooth, audio, voice, llm, integrations, core-logging}
E = {
  app → bluetooth,
  app → audio,
  app → voice,
  app → llm,
  app → integrations,
  app → core-logging,
  audio → core-logging,
  voice → audio,
  voice → core-logging,
  llm → core-logging,
  integrations → core-logging
}

Propriedades:
- Acíclico: SIM (DAG) ✅
- core-logging: nó sink (grau de saída = 0)
- app: nó source (grau de entrada = 0 de outros módulos)
- Componentes fortemente conectados: cada módulo é seu próprio SCC (DAG)

Máquina de Estados Principal

VoicePipeline States

S = {IDLE, RECORDING, TRANSCRIBING, QUERYING_LLM, SPEAKING, ERROR}

Transições δ:
IDLE + startRecording → RECORDING
RECORDING + stopRecording → TRANSCRIBING
RECORDING + error → ERROR
TRANSCRIBING + sttResult(text) → QUERYING_LLM
TRANSCRIBING + sttResult(empty) → ERROR (auto-reset em 3s → IDLE)
TRANSCRIBING + error → ERROR
QUERYING_LLM + llmResult → SPEAKING
QUERYING_LLM + error → ERROR
SPEAKING + ttsComplete → IDLE
ERROR + timeout(3s) → IDLE
ERROR + userReset → IDLE

Propriedades verificadas:
✅ Sem estados inalcançáveis (todos estados têm caminho de IDLE)
✅ Sem deadlocks (todos estados têm transição de saída)
✅ Auto-healing: ERROR sempre resolve para IDLE
⚠️  SPEAKING não tem cancel — bloqueio possível se TTS travar

BluetoothController States

S = {DISCONNECTED, SCANNING, CONNECTING, CONNECTED, SCO_CONNECTING, SCO_ACTIVE, ERROR}

Prioridade de fonte de áudio (função monotônica):
priority: AudioSource → 
  BLE_AUDIO  → 5
  BT_SCO     → 4
  USB_MIC    → 3
  WIRED      → 2
  BUILTIN    → 1

Invariante: currentSource = argmax{priority(s) | s ∈ availableSources}

Análise de Concorrência

Coroutine Scopes

viewModelScope (MainViewModel):
- Lifecyle: vinculado ao ViewModel, cancelado onCleared()
- Dispatchers: Main para UI, IO para rede/disk, Default para CPU

Padrões identificados:
- StateFlow<VoicePipelineState> como bus de eventos centralizdo
- collect { } em LaunchedEffect nas telas Compose
- MutableStateFlow com atomic updates (thread-safe)

Riscos potenciais:
- SharedFlow sem replay: eventos podem ser perdidos se collector lento
- launch { } sem supervisorScope: falha cancela todos os filhos
- withContext(Dispatchers.IO) aninhado: overhead desnecessário de contexto

AuriToolExecutor — Análise de Idempotência

9 ferramentas:
1. alarm    — NÃO idempotente (cria alarmes duplicados)
2. calendar — NÃO idempotente (cria eventos duplicados)
3. reminder — NÃO idempotente
4. time     — Idempotente (read-only)
5. email    — NÃO idempotente (pode enviar duplicado)
6. draft    — Quase idempotente (draft com mesmo conteúdo)
7. call     — NÃO idempotente (inicia chamada)
8. whatsapp — NÃO idempotente
9. app      — Idempotente se app já aberto

Risco: sem deduplicação, retry logic pode causar ações duplas
Recomendação: implementar idempotency keys por ferramenta

Análise de Performance

Pipeline de Latência (E2E medido no A04)

Componente          Latência típica    Modelo
──────────────────────────────────────────────
Audio capture       ~100ms             determinístico
STT (online)        200-800ms          distribuição log-normal
STT (Vosk offline)  N/A (stub)         —
LLM (Ollama A04)    10-15s             alta variância (~3 tok/s)
LLM (OpenAI API)    1-3s               distribuição gamma
TTS                 50-200ms           determinístico

E2E latência total (Ollama A04): μ ≈ 12s, σ ≈ 3s
E2E latência total (OpenAI): μ ≈ 2.5s, σ ≈ 0.8s

Modelo de fila M/M/1 para pipeline LLM:
- λ (taxa de requisições): ~0.1 req/s (1 a cada 10s em uso típico)
- μ (taxa de serviço Ollama A04): ~0.08 req/s
- ρ = λ/μ = 1.25 > 1 → INSTÁVEL sob carga contínua!
- ρ (OpenAI) ≈ 0.3 → ESTÁVEL com buffer adequado

Consumo de Memória

Estimativa por componente:
- App base: ~50MB
- Bluetooth stack: ~5MB
- Audio buffer (PCM, 16kHz, 16-bit, 5s): ~160KB
- STT model (Android): ~2MB (online) / ~50MB (Vosk)
- LLM context (OpenAI/Claude): apenas tokens (rede)
- LLM local (llama3.2:1b): ~800MB RAM

Total com Ollama local: ~850MB → crítico em dispositivos 2GB RAM

Análise de Segurança

Superfície de Ataque

1. API Keys: EncryptedSharedPreferences (AES-256-GCM) ✅
2. Bluetooth SCO: comunicação de voz sem criptografia (design limitation) ⚠️
3. HTTP cleartext (Ollama localhost): permitido explicitamente via network_security_config ⚠️
4. LAN access: cleartext permitido para 192.168.*.* — risco em redes públicas ❌
5. Gmail OAuth2 tokens: persistidos em token store — verificar criptografia
6. Audio recording: exige permissão RECORD_AUDIO — verificar escopo temporal

Pontos de Alta Complexidade

LlmClientFactory (complexidade ciclomática alta)

Função: factory(provider, context) → LlmClient
Branches:
- 11 providers (OPENAI, CLAUDE, GEMINI, AI_STUDIO, OLLAMA, STUB + 5 RPA variants)
- Context nullable vs non-null
- Config (base_url, model) presente vs ausente

Complexidade ciclomática estimada: CC ≈ 15-20
Recomendação: refatorar para Strategy + Registry pattern

MainViewModel (God Object potential)

Responsabilidades identificadas:
1. Orquestração de VoicePipeline
2. Gerenciamento de LLM provider selection
3. Estado de Bluetooth
4. Histórico de conversas
5. Tool execution proxy
6. Settings sync

Violação do SRP (Single Responsibility Principle)
Solução: decomposição em sub-ViewModels especializados

Invariantes Globais do Sistema

GLOBAL-INV-01:
  Em todo momento, no máximo 1 foreground service ativo para recording
  Formalmente: |{s ∈ Services | s.isRecording = true}| ≤ 1

GLOBAL-INV-02:
  API key nunca é transmitida em logs
  Formalmente: ∀ log entry l: ¬contains(l.text, apiKey)

GLOBAL-INV-03:
  SCO connection existe sse isRecording = true E source = BT_SCO
  Formalmente: scoActive ↔ (isRecording ∧ audioSource = BT_SCO)

GLOBAL-INV-04:
  Pipeline sempre em estado definido (sem estado undefined/null)
  Formalmente: pipelineState ∈ S (definido acima, sem null)