ajuste no guardraild COE
This commit is contained in:
423
tests/docs/RELATORIO_POLITICAS_DE_LINHA_ALT1_ALT2.md
Normal file
423
tests/docs/RELATORIO_POLITICAS_DE_LINHA_ALT1_ALT2.md
Normal 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.
|
||||
Reference in New Issue
Block a user