Sigilo, e por que ele não é problema seu aqui
A Unidade 1 inteira foi construída em cima de uma linha:
TETO_SIGILO = 1 # 0 = Público 1 = Segredo de Justiça 2 = Sigilo Absoluto
E de uma regra: quem decide o que o agente pode ver é o seu código, não o modelo. O teto era uma constante no WHERE, nunca um argumento de Tool, porque um argumento é algo que o modelo escolhe — e o modelo obedece a quem escreveu a última linha do prompt.
Agora vem a pergunta natural: e na API do CNJ?
A resposta, medida
Duas consultas, feitas de forma independente uma da outra.
Primeiro, quantos processos do TJRJ existem no DataJud:
consultar({"size": 0, "track_total_hits": True, "query": {"match_all": {}}})
{'value': 23152022, 'relation': 'eq'}
Agora, a distribuição por nível de sigilo:
consultar({"size": 0,
"aggs": {"s": {"terms": {"field": "nivelSigilo", "size": 10}}}})
{"s": {"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [{"key": 0, "doc_count": 23152022}]}}
Um único balde. sum_other_doc_count: 0 — nada ficou de fora da contagem. E o número bate, dígito por dígito, com o total do acervo.
23.152.022 processos, 23.152.022 com nivelSigilo 0. Não é uma amostra que por acaso deu tudo público: é o acervo inteiro.
Por que é assim
Porque a filtragem acontece antes da API existir.
Quando o TJRJ envia dados ao CNJ, o processo de extração marca o nível de sigilo de cada processo — e os que têm segredo de justiça ou sigilo absoluto não entram no índice público. Existem na base do CNJ; não existem no api_publica_tjrj.
Ou seja: o controle de acesso que na Unidade 1 você escreveu na cláusula WHERE aqui já foi executado por outra pessoa, num estágio anterior do caminho do dado.
Por que o filtro continua no código, então
Olhe a Tool do próximo capítulo:
TETO_SIGILO = 0
corpo = {
"query": {"bool": {"filter": [
{"term": {"assuntos.nome.keyword": assunto}},
{"range": {"nivelSigilo": {"lte": TETO_SIGILO}}},
]}},
...
}
E, depois de receber a resposta:
for h in achados:
p = h["_source"]
# Cinto e suspensório: se algo com sigilo escapar da origem, para aqui.
if p.get("nivelSigilo", 99) > TETO_SIGILO:
continue
Duas verificações para uma coisa que já é garantida. Isso é desperdício?
Não, e a razão não é desconfiança do CNJ. São três:
1. A garantia é de terceiro, e pode mudar sem avisar. O que garante que só há nível 0 na API é uma decisão operacional do CNJ, não um contrato com você. Se amanhã o índice passar a incluir nível 1, seu código não fica sabendo. Com o filtro, ele simplesmente continua correto.
2. O .get("nivelSigilo", 99) protege contra o campo faltando. Você já viu sistema.nome vir "Inválido" no primeiro documento da primeira consulta. Um campo ausente vira 99, que é maior que o teto, e o processo é descartado. O padrão numa checagem de acesso é negar, não permitir.
3. É a linha que o leitor do seu código vai procurar. Quando alguém — o senhor mesmo, daqui a um ano — abrir essa Tool para adaptá-la ao sistema do Tribunal, a primeira pergunta vai ser "onde está o controle de acesso aqui?". Se a resposta for "não tem, porque a origem já filtra", a adaptação vai começar sem ele. E aí a origem não filtra mais.
Este é o ponto da unidade que vale para além do curso.
A Unidade 1 usava dado inventado, e o teto de sigilo era um exercício. Esta unidade usa dado real e o teto é redundante. Nenhuma das duas te expõe a nada.
O dia em que a Tool apontar para o banco do Tribunal, ela vai ver os três níveis — e aí a mesma linha, que até então nunca tinha feito diferença nenhuma, passa a ser a única coisa entre um agente e os autos de um processo criminal com a vítima identificada.
Escreva-a agora, enquanto ela é inofensiva. Quem escreve o controle de acesso depois, escreve depois do incidente.
O que o CNJ não tem
Vale ser explícito sobre o que essa API não devolve, porque isso define o alcance do agente que você está construindo:
| Existe no DataJud | Não existe |
|---|---|
| Número do processo | Nome das partes |
| Classe e assuntos (TPU) | Petição inicial |
| Órgão julgador e comarca | Sentenças e acórdãos |
| Data de ajuizamento | Qualquer PDF |
| Lista completa de movimentos | Valor da causa |
| Grau, formato, sistema de origem | Advogados |
É metadado processual. E é justamente por não ter nome de parte nem peça que ele pode ser público.
Para o uso que motivou este curso, isso basta: com número e órgão julgador, o magistrado abre o processo no sistema do Tribunal, onde tem — aí sim, com sua credencial nominal e o registro de acesso correspondente — tudo o que precisa.
Repare no desenho que se formou, quase sem querer.
O agente trabalha sobre metadado público e devolve ponteiros. O acesso ao conteúdo continua acontecendo no sistema do Tribunal, com a credencial do juiz e a trilha de auditoria dele.
Isso não é um contorno de limitação. É uma arquitetura melhor do que a alternativa — e é a resposta que você vai dar quando alguém, com toda razão, perguntar "mas esse agente aí vai ler os autos?".
A ponte para o acervo do Tribunal
O arquivo dados/MAPEAMENTO.md já descreve como as tabelas do TJRJ correspondem ao esquema da Unidade 1. Vale registrar o que muda quando a origem é interna:
| API do CNJ | Banco do Tribunal | |
|---|---|---|
| Níveis de sigilo presentes | Só 0 | 0, 1 e 2 |
| Quem filtrou | O CNJ, antes de publicar | Ninguém. Você. |
| Sua credencial | Chave pública, igual para todos | Nominal, com trilha de auditoria |
| Consequência de um filtro esquecido | Nenhuma | Acesso indevido a processo protegido |
| Onde o teto entra | Redundância defensiva | Único controle existente |
A coluna da direita é o segundo curso. A da esquerda é este.
O ponto pedagógico é que o código das duas colunas é o mesmo código. A linha nivelSigilo <= TETO_SIGILO não muda de forma ao trocar de origem: ela vira p.id_nivel_sigilo <= ? no SQLite, nivelSigilo no range do Elasticsearch, e uma cláusula equivalente no Oracle do EJUD. Muda a sintaxe; não muda a decisão.