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