# Correção de paridade conversacional residual do Contas — 2026-08-31 ## Escopo Correções pontuais extraídas do comportamento útil do Contas anterior sem restaurar o runtime legado: - retenção antes de handoff humano; - jurídico/Anatel/Procon com dependência de entidade previamente em foco; - três falas consecutivas realmente incompreensíveis; - preservação do pós-finalização no framework, com status terminal de erro respeitado; - cancelamento múltiplo por entidades nomeadas/contextuais e por "todos os VAS avulsos". ## Arquitetura Foi adicionada `app/domain/contas/conversation_policy.py`, executada depois do `EnterpriseRouter` e antes do agente de domínio. A policy não executa side effects: apenas reprompta, enriquece contexto ou altera o roteamento. Toda operação transacional continua passando pelo `AgentRuntimeMixin`, pré-validação MCP, confirmação explícita e workflow do Contas. ## Retenção Quando o router solicita handoff humano, a policy procura evidência autoritativa de VAS avulso que participou da variação da conta usando `varied_avulso_items`. Sem evidência, o handoff segue normalmente. Com evidência, a policy oferece dois degraus: explicação da variação e, em seguida, tratamento dos VAS identificados. Recusa do segundo degrau leva ao handoff humano normal. O aceite do tratamento cria reentrada contextual com os nomes já comprovados; o cliente não precisa repeti-los e a transação continua sujeita à pré-validação e confirmação. ## Jurídico / Anatel / Procon A mera ameaça regulatória não cria uma transação. Sem entidade concreta em foco, a fala é encaminhada como reclamação ampla ao suporte, sem MCP transacional. Quando já existe `subject/items` em estado transacional, o foco é preservado e a fala pode continuar no fluxo correspondente. A fatura inteira nunca é usada para inventar o alvo. ## Três falas incompreensíveis Foi criada a intent semântica `contas_no_match`, exclusiva para fala sem conteúdo recuperável. `fallback` genérico não conta como incompreensão. O contador é consecutivo e reinicia em qualquer turno compreendido. - 1ª: pede reformulação; - 2ª: pede reformulação; - 3ª: encerra pelo nó global `end_session`, chamando `finalizar_atendimento` com `status=erro_no_match`. O limite pode ser configurado por `CONTAS_NO_MATCH_MAX_CONSECUTIVE`, default 3. ## Cancelamento múltiplo `validar_vas_subject` agora resolve múltiplas entidades exclusivamente contra catálogo autorizado VAS/fatura. Exemplos suportados após extração semântica contextual: - `cancela Netflix e HBO`; - `os dois` / `ambos`, quando o extrator LLM consegue resolver os nomes pelo contexto imediato; - `todos os VAS avulsos`. `todos` genérico não expande em massa. Para "todos os VAS avulsos", itens estratégicos/bundle são filtrados pela política de domínio. Os itens resolvidos são enviados como `items[]` para o workflow batch existente, com uma única confirmação explícita antes da execução. ## Pós-finalização Não foi criado runtime duplicado. O lifecycle continua no framework. O nó `end_session` passou apenas a respeitar um `terminal_status` já definido pela policy (por exemplo `erro_no_match`) e uma mensagem terminal específica, mantendo o mecanismo atual de replay/soft reset. ## Testes Novos testes: - `tests/migration/test_contas_conversation_policy_residuals.py`; - `tests/migration/test_multiple_vas_subject_resolution.py`. Regressão direcionada: **61 PASS**. Regressão completa `tests/migration`: **810 PASS / 2 FAIL**. Os mesmos dois FAIL foram reproduzidos no ZIP original sem estas alterações, portanto são falhas preexistentes e fora do escopo desta correção: 1. `test_validar_contestacao_aprova_quando_item_e_valor_sao_comprovados`; 2. `test_termino_desconto_e_valor_divergente_preservam_semantica_do_original`.