# B2BCall — Troubleshooting Problemas reais encontrados durante o desenvolvimento deste projeto e como foram diagnosticados/resolvidos — mantido como referência para o futuro. ## "Argument calledNumber is missing" ao originar chamada **Sintoma**: `PrismaClientValidationError` ao reservar um lead, mesmo a query SQL parecendo correta. **Causa**: `$queryRaw` do Prisma **não aplica** o mapeamento camelCase automático que `findMany`/`update` aplicam — colunas retornadas por SQL cru mantêm o nome exato da coluna (`phone_normalized`, não `phoneNormalized`). **Fix**: sempre usar alias explícito no SQL: `phone_normalized AS "phoneNormalized"`. Ver `apps/dialer-worker/src/lead-repository.ts`. ## Pacing do discador oscilando/nunca parando de subir mesmo sem atividade **Sintoma**: no cenário de teste da seção 66 (20 agentes/10 CPS/30% taxa de atendimento), o `pacingFactor` continuava subindo mesmo em períodos ociosos, gerando concorrência muito acima do esperado. **Causas** (três, compostas): 1. O cálculo de concorrência total não incluía chamadas já conectadas ao agente (`agentConnectedCalls`), subestimando quanto já estava "em uso". 2. O ajuste de pacing subia mesmo sem nenhuma atividade de discagem no ciclo (nada "deu errado", então ele interpretava como "pode subir mais"). 3. Uma única iteração fechava 100% da diferença entre o alvo e o atual, causando overshoot. **Fix**: `agentConnectedCalls` entra no total de concorrência; pacing nunca sobe durante ociosidade (`hasActivity` gate); fechamento de gap limitado a 50% por ciclo (`RAMP_FRACTION`); e dampening por raiz quadrada do próprio `pacingFactor`. Ver `apps/dialer-worker/src/predictive-engine.ts` e `docs/PREDICTIVE_DIALER.md`. ## AMI: comando `Command` não retorna o output esperado **Sintoma**: parsing manual do protocolo AMI para a action `Command` (usada por diagnóstico) não batia com a documentação legada (`Response: Follows` / `--END COMMAND--`). **Causa**: o Asterisk 22 usa um formato diferente para `Command`: múltiplos headers `Output:` repetidos, um por linha de saída — não o bloco `Follows`/`END COMMAND` de versões antigas. **Fix**: reverse-engineering via socket TCP cru (script de debug dedicado) para confirmar o formato real antes de implementar o parser em `packages/telephony`. ## Erro de sintaxe no `schema.prisma`: `@default(1_000_000)` **Sintoma**: `prisma generate` falha com erro de parsing. **Causa**: separador de milhar com underscore (`1_000_000`) não é suportado na sintaxe do `.prisma` — é um recurso de JS/TS, não do DSL do Prisma. **Fix**: escrever o número sem separadores: `1000000`. ## `Prisma.InputJsonValue` rejeita instância de DTO **Sintoma**: `Index signature for type 'string' is missing` ao passar um objeto DTO diretamente para um campo `Json` do Prisma (ex.: `AuditLog.after`). **Causa**: uma instância de classe (mesmo com os campos certos) não satisfaz a assinatura de índice que `InputJsonValue` exige — só um objeto literal simples satisfaz. **Fix**: espalhar em um objeto literal: `after: { ...dto }` em vez de `after: dto`. ## Redis: agentes travados em `IN_CALL` para sempre **Sintoma**: depois de uma chamada, o agente nunca voltava a `AVAILABLE`. **Causa**: o "claim" de agente disponível só marcava `IN_CALL` na conexão — não havia nenhum mecanismo simétrico de liberação após o fim da chamada. **Fix**: `agent-call-binding.ts#releaseAgentAfterCall`, chamado explicitamente quando a chamada termina, com suporte a `WRAP_UP` intermediário antes de `AVAILABLE`. ## Corrida entre duas campanhas reivindicando o mesmo agente **Sintoma** (encontrado em revisão de código, não em produção): implementação inicial de `claimAvailableAgent` usava `findFirst` + update separado — janela de corrida entre duas campanhas concorrentes. **Fix**: reescrito com `UPDATE ... WHERE id = (SELECT ... FOR UPDATE SKIP LOCKED LIMIT 1) RETURNING ...`, mesmo padrão atômico já usado para reserva de leads. ## Diagnóstico geral Para qualquer problema não listado acima: 1. `bash scripts/healthcheck.sh` — descarta problema de infraestrutura básica primeiro. 2. `docker compose logs -f ` — logs estruturados JSON, procurar por `"level":50` (error) ou `"level":40` (warn). 3. `docker exec b2bcall-asterisk asterisk -rx "..."` — ver `docs/ASTERISK.md` para comandos úteis. 4. Consultar `AuditLog` (`GET /api/audit`) se o problema envolve uma ação específica de um usuário. 5. Verificar `docker compose ps` — um container "unhealthy" quase sempre aponta a causa raiz de problemas em cascata nos serviços que dependem dele.