Ajustes no agente de contas

This commit is contained in:
2026-08-31 14:13:51 -03:00
parent 00ac7f0c83
commit 87a0b77dae
137 changed files with 715 additions and 8 deletions

View File

@@ -0,0 +1,27 @@
# Correções após regressão de 31/08/2026
Esta rodada corrige quatro comportamentos observados no relatório de regressão sem reintroduzir o runtime conversacional legado.
## 1. Cancelamento múltiplo após confirmação
O snapshot transacional do framework já preservava corretamente os argumentos confirmados. O defeito estava no preflight de execução do MCP do Contas, que tentava resolver novamente o `subject` de apresentação (por exemplo, `Tamboro Mensal, Paramount+`) mesmo quando `items[]` já continha múltiplas entidades canônicas pré-validadas. Agora `items[]` é a fonte de verdade nessa condição e não há segunda resolução textual.
## 2. Contestação com valor incompatível
Uma divergência de valor comprovada pelo CVAL passa a ser recuperável: o item permanece preservado, apenas `valor` volta para coleta e a resposta informa o valor autoritativo encontrado na fatura. O contrato de auditoria mantém `reason=CVAL` e acrescenta `recoverable_reason=amount_not_supported_by_invoice`.
O runtime genérico ganhou suporte opcional a `parameter_message` emitido por um pre-validator de domínio. O framework apenas apresenta essa mensagem enquanto permanece em `COLLECTING_PARAMETERS`; ele não interpreta a regra de negócio.
## 3. Encerramento explícito
Expressões inequívocas como `entendi, obrigado, era só isso` encerram a sessão como `resolvido`, desde que não exista transação ou workflow ativo. Isso evita que uma despedida caia em fallback/guardrail sem consumir confirmações pendentes.
## 4. Continuação plural após explicação de fatura
Frases como `as duas mesmo, pode seguir` imediatamente após `contas_invoice_explanation` permanecem no contexto de explicação e não são confundidas com finalização genérica.
## Regressão
- Testes novos e direcionados: 58/58 no Contas e 30/30 no runtime transacional do framework.
- `tests/migration`: 818 PASS / 2 FAIL.
- Os 2 FAIL restantes são preexistentes nesta base: caso histórico de `validar_contestacao` com TIM Fashion/R$50 e fraseologia de `termino_desconto`.

View File

@@ -0,0 +1,63 @@
# 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`.