Ajustes conforme relatorio de testes 2026-08-27

This commit is contained in:
2026-08-29 09:53:32 -03:00
parent 0ecff719b7
commit 88e1f070d7
791 changed files with 27040 additions and 29038 deletions

View File

@@ -0,0 +1,423 @@
# Relatório técnico — políticas alternativas de operação por linha
## 1. Objetivo
O Agent Contas possui duas políticas alternativas para controlar operações em uma linha (MSISDN) diferente da linha identificada/autenticada no início do atendimento.
A implementação permanece no **Agent Contas/MCP Contas**, sem regra TIM hardcoded no core do `agent_framework_oci`.
A política ativa entregue no projeto continua sendo a **ALT1 — somente a linha autenticada**.
A ALT2 foi evoluída para não inferir autorização a partir de fatura, billing ou texto do cliente. Ela depende de uma fonte explícita de autorização: a nova tool MCP mock `consultar_linhas_autorizadas`.
## 2. Políticas disponíveis
### 2.1 ALT1 — `authenticated_line_only` — PADRÃO
Fonte:
```text
contas_mcp/servers/contas_mcp_server/line_policy_alt1.py
```
Comportamento:
- a linha operacional continua sendo a linha identificada pelo `business_context` da chamada;
- uma linha citada em texto livre **não substitui** a identidade da sessão;
- se o cliente mencionar explicitamente outra linha — número completo ou referência como `final 4321` — a execução é bloqueada antes de qualquer operação de domínio;
- o bloqueio é terminal para o turno e interrompe as tools seguintes;
- a mensagem devolvida é:
```text
Por segurança, este atendimento só permite consultar ou realizar operações na linha identificada na chamada. Não posso usar outra linha informada na conversa.
```
Exemplo:
```text
linha autenticada: 11999999999
cliente: "quero cancelar o streaming do número da minha esposa, final quatro três dois um"
resultado:
LINE_POLICY_BLOCKED / other_line_not_allowed
nenhuma consulta/cancelamento é executado para a outra linha
```
### 2.2 ALT2 — `authorized_related_lines`
Fonte:
```text
contas_mcp/servers/contas_mcp_server/line_policy_alt2.py
```
Comportamento:
- a linha autenticada continua sendo a origem de confiança;
- uma outra linha só pode ser usada se for retornada pelo serviço explícito `consultar_linhas_autorizadas`;
- referências como `final 4321` são resolvidas somente contra as linhas autorizadas retornadas por esse serviço;
- se houver exatamente uma correspondência, ela vira o `effective_msisdn` da operação;
- se não houver correspondência, a operação é bloqueada;
- se houver mais de uma correspondência, o fluxo exige esclarecimento;
- se o serviço de linhas autorizadas falhar, o ALT2 opera em **fail-closed**: somente a linha autenticada permanece autorizada;
- a presença de um MSISDN em `invoice_detail`, `billing_analysis` ou outra evidência de cobrança **não concede autorização operacional**;
- um número pronunciado pelo cliente também **não concede autorização**.
Exemplo:
```text
linha autenticada: 11999999999
consultar_linhas_autorizadas retorna:
- 11999999999 (titular)
- 11988884321 (dependente autorizado)
cliente: "quero cancelar o TIM Fashion da linha final 4321"
resultado ALT2:
requested reference = 4321
effective_msisdn = 11988884321
operação pode prosseguir nessa linha
```
## 3. Novo serviço MCP mock — `consultar_linhas_autorizadas`
### 3.1 Objetivo
Foi criada uma tool MCP side-effect-free para representar a integração que, em produção, deve consultar um serviço de identidade/conta e responder **quais linhas o atendimento autenticado está autorizado a operar**.
Tool:
```text
consultar_linhas_autorizadas
```
Registro MCP:
```text
contas_mcp/servers/contas_mcp_server/main.py
```
Implementação mock:
```text
contas_mcp/servers/contas_mcp_server/authorized_lines_service.py
```
Fixture mock:
```text
app/domain/contas/fixtures/authorized_lines.json
```
### 3.2 Contrato de entrada
A consulta parte da identidade já autenticada no atendimento. O cliente não informa qual linha deve ser autorizada.
Exemplo:
```json
{
"msisdn": "11999999999",
"customer_key": "11999999999",
"contract_key": "3000131180"
}
```
O `msisdn` acima é a linha autenticada/original da chamada.
### 3.3 Contrato de saída mock
```json
{
"success": true,
"status": "SUCCESS",
"source": "mock",
"authenticated_msisdn": "11999999999",
"authorized_lines": [
{
"msisdn": "11999999999",
"relationship": "titular",
"status": "ACTIVE",
"authorized": true
},
{
"msisdn": "11988884321",
"relationship": "dependente",
"status": "ACTIVE",
"authorized": true
}
],
"authorized_msisdns": [
"11999999999",
"11988884321"
]
}
```
### 3.4 Por que existe uma tool MCP separada
O objetivo é deixar explícita a arquitetura de produção:
```text
identidade autenticada da chamada
consultar_linhas_autorizadas
serviço legado/CRM/IAM/conta
lista de linhas realmente autorizadas
line_policy_alt2
resolve referência conversacional
0 matches → bloqueia/clarifica
1 match → effective_msisdn
>1 matches → clarifica
```
A autorização não pertence ao LLM. O LLM/text extractor pode interpretar `final 4321`, mas não decide se `4321` é uma linha autorizada.
### 3.5 Comportamento em produção
O arquivo `authorized_lines_service.py` é propositalmente um mock de referência. Em produção, ele deve ser substituído por um adapter que consulte o serviço corporativo responsável pela relação titular/dependentes/linhas autorizadas.
O contrato recomendado deve preservar pelo menos:
```text
success
authenticated_msisdn
authorized_lines[].msisdn
authorized_lines[].status
authorized_lines[].authorized
authorized_lines[].relationship
authorized_msisdns
```
Se a integração real falhar ou não puder provar a autorização da outra linha, o comportamento esperado do ALT2 é fail-closed.
## 4. Fluxo ALT2 atualizado
O fluxo completo ficou:
```text
mensagem do cliente
extrai requested_line_reference
ex.: suffix=4321
business_context mantém 11999999999
MCP detecta ALT2 ativo
consultar_linhas_autorizadas(11999999999)
authorized_lines_evidence
line_policy_alt2
resolve 4321 somente contra authorized_lines_evidence
effective_msisdn = 11988884321
só então a tool/workflow de negócio é executada
```
A ALT2 não usa mais `invoice_detail`, `billing_analysis` ou `complete_invoices_payload` como fonte de **autorização** de linha.
## 5. Política ativa
O MCP importa sempre:
```text
contas_mcp/servers/contas_mcp_server/line_policy.py
```
No pacote entregue, `line_policy.py` é uma cópia exata de `line_policy_alt1.py`.
Portanto, **o comportamento corrente permanece bloqueando operações em outra linha**.
O `/health` informa a política carregada:
```json
{
"line_policy": "authenticated_line_only",
"line_policy_description": "Somente a linha identificada/autenticada na chamada pode ser consultada ou alterada."
}
```
## 6. Como ativar ALT1
Forma recomendada:
```bash
python scripts/select_line_policy.py alt1
```
Depois reinicie o backend/MCP Server.
Linux/macOS:
```bash
cp contas_mcp/servers/contas_mcp_server/line_policy_alt1.py \
contas_mcp/servers/contas_mcp_server/line_policy.py
```
PowerShell:
```powershell
Copy-Item `
contas_mcp/servers/contas_mcp_server/line_policy_alt1.py `
contas_mcp/servers/contas_mcp_server/line_policy.py -Force
```
## 7. Como ativar ALT2
```bash
python scripts/select_line_policy.py alt2
```
Depois reinicie o backend/MCP Server.
Ao iniciar com ALT2, o MCP passa a consultar automaticamente `consultar_linhas_autorizadas` quando houver uma referência explícita a linha no turno.
Não é necessário inserir manualmente:
```python
context["authorized_msisdns"] = [...]
```
nem:
```python
args["authorized_msisdns"] = [...]
```
A lista vem do serviço MCP de autorização.
## 8. Como alterar o mock para testes
Para ilustrar outra linha autorizada, edite apenas:
```text
app/domain/contas/fixtures/authorized_lines.json
```
Exemplo:
```json
{
"msisdn": "11977771234",
"relationship": "dependente",
"status": "ACTIVE",
"authorized": true
}
```
Não altere `line_policy_alt2.py` para cadastrar linhas.
Esse desenho deixa claro que a política apenas **consome autorização**; ela não é o cadastro das linhas autorizadas.
## 9. Abrangência
A política é aplicada no ponto único `_invoke()` do MCP Contas antes da execução de domínio. Dessa forma cobre as tools/serviços baseados em MSISDN, inclusive quando passam por workflows.
Cobertura funcional inclui:
- `consultar_faturas`
- `consultar_plano`
- `invoice_explanation`
- `consultar_vas`
- `consultar_historico_vas`
- `cancelar_vas_avulso`
- `tratar_vas_estrategico`
- `validar_vas_subject`
- `validar_contestacao`
- `contestar_cobranca`
- `pro_rata`
- `termino_desconto`
- `valor_divergente`
- `consultar_status_solicitacao`
- `enviar_sms`
- `recuperar_fatura_pdf`
- `finalizar_atendimento`
`consultar_linhas_autorizadas` é a fonte de autorização da ALT2 e não passa pela própria política para evitar dependência circular.
`buscar_informacao` não depende de linha e `retomar_workflow` apenas retoma execução já iniciada.
## 10. Arquivos alterados/criados
### Política de linha
```text
contas_mcp/servers/contas_mcp_server/line_policy.py
contas_mcp/servers/contas_mcp_server/line_policy_alt1.py
contas_mcp/servers/contas_mcp_server/line_policy_alt2.py
```
### Novo serviço MCP de autorização
```text
contas_mcp/servers/contas_mcp_server/authorized_lines_service.py
app/domain/contas/fixtures/authorized_lines.json
contas_mcp/servers/contas_mcp_server/main.py
```
### Referência conversacional e seleção da política
```text
app/domain/contas/line_reference.py
scripts/select_line_policy.py
```
### Testes e documentação
```text
tests/migration/test_line_policy_alternatives.py
docs/RELATORIO_POLITICAS_DE_LINHA_ALT1_ALT2.md
```
## 11. Validação
Testes específicos da política e do novo mock:
```text
12 passed
```
Smoke ALT2:
```text
policy = authorized_related_lines
authorized = [11999999999, 11988884321]
requested = final 4321
allowed = true
effective = 11988884321
```
Após o smoke, ALT1 foi restaurado e validado como política ativa entregue.
Suíte completa de migração com ALT1 ativa:
```text
765 passed
```
## 12. Decisão arquitetural
Responsabilidades finais:
| Camada | Responsabilidade |
|---|---|
| Framework | identidade/contexto, execução genérica, terminalidade e short-circuit de tools |
| Agent/MCP Contas | política ALT1/ALT2 e integração de autorização |
| `consultar_linhas_autorizadas` | informar quais linhas a identidade autenticada está autorizada a operar |
| Backend real futuro | fonte de verdade de titular/dependentes/autorização |
| LLM | interpretar a referência conversacional; nunca conceder autorização |
A principal regra arquitetural é:
> **linha mencionada ≠ linha autorizada**
A autorização precisa vir de uma fonte explícita e confiável. Na versão demonstrativa essa fonte é o mock MCP `consultar_linhas_autorizadas`; em produção, deve ser substituída pela integração corporativa correspondente.