# 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.