# Da base sintética para a base real do Tribunal

Este documento explica como sair do `acervo.db` do curso e apontar o mesmo Agent para os dados reais do Tribunal.

Ele é escrito para quem tem — ou consegue solicitar — credencial de leitura em uma base do TJRJ.

---

## 1. Por que a base do curso é sintética

Três razões, nesta ordem de importância:

1. **Reprodutibilidade.** Todo aluno gera exatamente a mesma base (a semente aleatória é fixa em `42`). Quando um exercício dá resultado diferente do esperado, a causa está no código do aluno, não nos dados. Isso é o que permite a aula funcionar.
2. **Nenhum dado de parte em sala.** Ninguém precisa de autorização para rodar os exercícios, e nada sensível é copiado para máquina de treinamento.
3. **O erro é seguro.** Você vai escrever *Tools* erradas — é assim que se aprende. Errar contra dados fictícios não tem consequência.

Todos os dados são gerados aleatoriamente. Os **números de processo, no entanto, são estruturalmente válidos**: seguem o formato `NNNNNNN-DD.AAAA.J.TR.OOOO` da Resolução CNJ nº 65/2008, com dígito verificador correto (módulo 97, ISO 7064). Eles não correspondem a processo nenhum, mas passam em qualquer rotina de validação de formato.

Os **códigos de assunto e classe são fictícios** e não correspondem à Tabela Processual Unificada do CNJ. Ao migrar para a base real, é o primeiro item a substituir.

---

## 2. O modelo do curso

```
                    ┌──────────────────┐
                    │   dim_assunto    │
                    └────────┬─────────┘
                             │
              ┌──────────────┴───────────────┐
              │  ponte_processo_assunto      │   (N:N, com flag "principal")
              └──────────────┬───────────────┘
                             │
  ┌────────────────┐   ┌─────┴──────────┐   ┌──────────────────────┐
  │   dim_classe   ├───┤ fato_processo  ├───┤ dim_orgao_julgador   │
  └────────────────┘   └─────┬──────┬───┘   └──────────────────────┘
                             │      │
        ┌────────────────────┘      └──────────────┐
        │                                          │
  ┌─────┴────────────┐                    ┌────────┴─────────┐
  │ fato_movimento   │                    │ dim_nivel_sigilo │
  └──────────────────┘                    └──────────────────┘
```

A consulta central do curso — "processos mais recentes sobre um assunto" — é esta:

```sql
SELECT
    p.numero_processo,
    p.data_distribuicao,
    p.situacao,
    o.nome        AS orgao_julgador,
    o.comarca,
    c.nome        AS classe,
    a.nome        AS assunto,
    s.nome        AS nivel_sigilo
FROM fato_processo p
JOIN ponte_processo_assunto pa ON pa.id_processo = p.id_processo AND pa.principal = 1
JOIN dim_assunto          a  ON a.id_assunto      = pa.id_assunto
JOIN dim_classe           c  ON c.id_classe       = p.id_classe
JOIN dim_orgao_julgador   o  ON o.id_orgao        = p.id_orgao
JOIN dim_nivel_sigilo     s  ON s.id_nivel_sigilo = p.id_nivel_sigilo
WHERE a.codigo = ?
  AND p.id_nivel_sigilo <= ?      -- teto de sigilo de quem consulta
ORDER BY p.data_distribuicao DESC
LIMIT ?;
```

Guarde a forma dela. Na base real, mudam os nomes — não a estrutura.

---

## 3. Descobrindo o modelo real

Os sistemas do Tribunal (PJe, DCP/EJUD, SEEU, e o data warehouse corporativo) têm cada um a sua modelagem, e os nomes de tabela variam. Não existe um mapa único — você precisa levantar o seu.

### 3.1 Peça o dicionário de dados

É o caminho mais curto, e existe. Ao abrir o chamado, peça explicitamente:

- O **dicionário de dados** ou modelo lógico do sistema que interessa.
- Uma **credencial somente leitura** (veja a seção 5 sobre por que isso importa).
- A indicação de **quais views são as homologadas para consulta analítica**. Bases transacionais costumam ter views prontas para relatório; usá-las evita que você reconstrua regras de negócio que já estão implementadas.

### 3.2 Explore o catálogo

Com a credencial em mãos, o catálogo do banco responde muita coisa. Em Oracle:

```sql
SELECT table_name FROM all_tables
WHERE owner = 'SEU_SCHEMA' AND table_name LIKE '%PROCESS%'
ORDER BY table_name;

SELECT column_name, data_type FROM all_tab_columns
WHERE table_name = 'TABELA_QUE_VOCE_ACHOU'
ORDER BY column_id;
```

Em PostgreSQL ou SQL Server, o equivalente padrão:

```sql
SELECT table_schema, table_name FROM information_schema.tables
WHERE table_name ILIKE '%process%';

SELECT column_name, data_type FROM information_schema.columns
WHERE table_name = 'tabela_que_voce_achou';
```

### 3.3 Preencha o mapa

Copie esta tabela e complete a última coluna conforme for descobrindo. Ela é o que você vai usar para reescrever as *Tools*.

| Conceito | No curso (`acervo.db`) | Na sua base (preencher) |
|---|---|---|
| Tabela-fato dos processos | `fato_processo` | |
| Número único do processo | `numero_processo` | |
| Data de distribuição | `data_distribuicao` | |
| Data do último movimento | `data_ultimo_mov` | |
| Situação / fase | `situacao` | |
| Dimensão de assunto | `dim_assunto` | |
| Código do assunto (TPU/CNJ) | `dim_assunto.codigo` | |
| Nome do assunto | `dim_assunto.nome` | |
| Relação processo × assunto | `ponte_processo_assunto` | |
| Marcação do assunto principal | `ponte_processo_assunto.principal` | |
| Dimensão de classe | `dim_classe` | |
| Dimensão de órgão julgador | `dim_orgao_julgador` | |
| Comarca | `dim_orgao_julgador.comarca` | |
| **Nível de sigilo** | `dim_nivel_sigilo` | |
| Tabela de movimentos | `fato_movimento` | |

<!-- Ao preencher, anote também o nome da VIEW homologada, se houver. -->

### 3.4 Substitua os códigos de assunto

Os códigos do curso (`1001` para violência doméstica, etc.) são inventados. Na base real, use os códigos da **Tabela Processual Unificada** do CNJ, instituída pela Resolução CNJ nº 46/2007. Ela é pública e consultável no portal do CNJ — e é provável que a sua base já traga o código da TPU na própria dimensão de assunto.

Confirme com uma consulta antes de confiar: procure o assunto pelo nome e veja qual código vem junto.

---

## 4. Sigilo: a parte que não pode dar errado

Esta é a diferença mais importante entre o exercício e a vida real, e o motivo de o `dim_nivel_sigilo` existir na base do curso desde o começo.

Processos em segredo de justiça — e criminais em particular — têm restrição de acesso que alcança **o próprio número do processo**, porque a partir dele se chega à identificação das partes. Um agente que devolva uma lista de números sem filtro pode expor exatamente aquilo que o segredo protege, mesmo sem exibir nome nenhum.

### 4.1 O filtro não pertence ao agente

**Regra:** o controle de acesso é responsabilidade do banco de dados, não da *Tool*, e muito menos do LLM.

Motivo: uma *Tool* que consulta tudo e filtra depois já leu o dado restrito. Se ela tiver um bug, se alguém alterar um parâmetro, ou se o modelo for induzido a chamar a função de outro jeito, o dado vaza. E um LLM é, por construção, persuadível — ele não é um mecanismo de segurança e não deve ser tratado como um.

Na prática, isso significa:

1. **A credencial já vem limitada.** Peça à TI um usuário cujo alcance corresponda ao seu nível de acesso. Se a base expõe uma view que já aplica a regra de sigilo, use a view, não a tabela.
2. **A *Tool* nunca recebe do modelo o teto de sigilo.** Esse valor vem da configuração da aplicação, associado a quem está operando — jamais de um argumento que o LLM possa preencher.
3. **Falhe fechado.** Se o nível de sigilo vier nulo ou desconhecido, trate como restrito e não retorne. O padrão nunca é "mostrar".

Compare:

```python
# ERRADO — o modelo escolhe o próprio nível de acesso.
def buscar_processos(assunto: str, nivel_sigilo_maximo: int = 2) -> list:
    ...
```

```python
# CERTO — o teto vem da sessão do usuário; o modelo só escolhe o assunto.
def buscar_processos(assunto: str, limite: int = 5) -> list:
    teto = sessao.nivel_de_acesso_do_usuario   # fora do alcance do LLM
    ...
```

### 4.2 Nunca entregue SQL livre ao modelo

É tentador criar uma *Tool* `executar_sql(consulta: str)` e deixar o LLM escrever a consulta. Não faça.

O modelo passa a poder ler qualquer tabela que a credencial alcance, contornando toda regra de sigilo que você tenha escrito, e o resultado é imprevisível de auditar. Ainda que a credencial seja somente leitura, "somente leitura de tudo" não é uma restrição útil aqui.

**O padrão correto:** *Tools* com parâmetros tipados e consultas parametrizadas, escritas por você. O modelo escolhe **qual** *Tool* chamar e **com quais valores** — nunca a consulta em si.

```python
# Consulta parametrizada: o valor entra como parâmetro, nunca concatenado.
cursor.execute(
    "SELECT ... WHERE a.codigo = ? AND p.id_nivel_sigilo <= ? LIMIT ?",
    (codigo_assunto, teto_sigilo, limite),
)
```

Concatenar valor em string de SQL abre injeção — e aqui a string vem de um texto gerado por modelo, ou seja, de um lugar sobre o qual você tem ainda menos controle do que sobre entrada de usuário.

### 4.3 O modelo tem que ser local

Todo dado que chega ao LLM entra no *prompt*. Se o modelo estiver em nuvem, cada número de processo consultado é transmitido a um terceiro.

Este curso usa Ollama local justamente por isso. Ao migrar para dados reais, **essa escolha deixa de ser preferência e passa a ser requisito**: nenhum resultado de consulta ao acervo deve ser enviado a um modelo hospedado fora da infraestrutura do Tribunal sem análise formal prévia.

### 4.4 Registre o que foi consultado

Em base real, guarde log de quem perguntou o quê e quais processos foram retornados. Se algum dia for preciso responder "como esse número chegou nesse relatório", o log é a única resposta possível.

---

## 5. Antes de apontar para produção — checklist

- [ ] Credencial é **somente leitura** (`SELECT`, sem `INSERT`/`UPDATE`/`DELETE`/DDL)
- [ ] A consulta usa a **view homologada**, se existir
- [ ] O teto de sigilo vem da **sessão**, não de argumento do modelo
- [ ] Nenhuma *Tool* aceita SQL livre
- [ ] Todas as consultas são **parametrizadas** (`?`), sem concatenação
- [ ] O modelo roda **localmente**
- [ ] Há `LIMIT` em toda consulta — o modelo pode pedir "todos"
- [ ] Consultas são **registradas em log**
- [ ] Foi testado primeiro em ambiente de **homologação**, não em produção
- [ ] O comportamento com sigilo foi verificado **explicitamente**: peça ao agente algo que ele não deveria poder ver e confirme que ele não vê

O último item é o que costuma ser esquecido. Teste o que o sistema **não** deve fazer, não apenas o que ele deve.
