Passo 1 de 2 da conciliacao das linhas do SAPL. A dev vinha da integracao
(hub, inventario, anexos, polls) e a 3.1.2 vinha do produto (assinatura, GED,
proposicao, Franco da Rocha). Nenhuma das duas continha a outra: a dev estava
33 commits a frente e 20 atras.
Traz os 20 commits que faltavam. Como a sp_importante_virou_urgente esta
inteiramente contida na 3.1.2 (zero commits exclusivos), ela vem junto e nao
precisa de merge proprio. As branches feature/add-agents-tracking e
feat/integracao-hub-app foram conferidas arquivo a arquivo e estao superadas:
o que adicionam (OnlyOffice, templates de documento, AGENTS.md, autor_nome no
poll) ja esta na dev por outro caminho.
O unico conflito real foi o docs/LOCALHOST_SETUP.md — dois roteiros escritos em
paralelo para a mesma tarefa. Resolvido a favor do roteiro da dev (mais novo,
validado em 13/08, com a arvore de decisao sobre migration), com tres ajustes:
- a nota sobre DEBUG foi corrigida. Ela dizia "DJANGO_DEBUG, nao DEBUG"; depois
deste merge o settings.py aceita as duas (linha 38, vindo da 3.1.2). Manter a
nota antiga seria documentar o codigo errado a partir de agora.
- "Problemas comuns" da 3.1.2 foi incorporado (alcance do banco remoto,
collectstatic com Gunicorn).
- as instrucoes que dependiam de docker/docker-compose-local.yml ficaram de
fora, com o motivo registrado no proprio documento: esse arquivo nao existe em
nenhuma das duas linhas.
Verificado no resultado do merge, e nao por suposicao:
- as quatro funcionalidades que so existiam na 3.1.2 chegaram inteiras — telas
de "Assinar Despachos em Lote" (docacessorio_assinar_lote, materia_assinar_lote),
preview PNG da pagina de assinatura (as tres funcoes), remocao de assinatura
(_pode_remover_assinatura) e o helper _carregar_certificado;
- nenhum marcador de conflito sobrou em .py, .md ou .html;
- sapl/materia e sapl/base compilam;
- todo nome importado de views_assinatura em urls.py e views.py existe — que era
o modo de falha mais perigoso aqui (urls.py importa no topo do modulo, entao
um nome faltando derruba o boot);
- a integracao da dev (sapl/integracao_hub) segue no lugar.
O passo 2 e a unificacao da assinatura: aplicar a delegacao da C3 por cima
mantendo as telas de lote com composicao local, decisao registrada em
docs-ia-projects#63.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Correcao de semantica (decisao do arquiteto, 17/08/2026): o que o vereador anexa
no app e evidencia da demanda — foto da rua, video da indicacao — nao o
documento legislativo. O codigo gravava o anexo como texto_original, o que faria
um video virar "texto" da proposicao.
- AnexoProposicao (app isolado, custo zero de rebase): arquivo + nome + mime +
tamanho + sha256 DOS BYTES RECEBIDOS — o SAPL declara o que guardou, fechando
a cadeia app -> hub -> legislativo. So gravacao por ora; consulta vem depois.
- limite de 1 arquivo removido (premissa errada); foto e video convivem
- texto_original volta a ser exclusivo do fluxo proprio do SAPL (tipo_texto '')
De quebra, conserta flakiness pre-existente dos testes: o baker criava usuario
com username de 150 chars e o auditing do SAPL grava em varchar(100) — o INSERT
do AuditLog estourava DENTRO do atomic e envenenava a transacao inteira.
Username explicito nos fixtures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
O hub nao guarda referencia por tramitacao — ele guarda a referencia da MATERIA.
Devolvendo so o id, o hub comparava id de tramitacao com id de materia e contava
o acervo inteiro como lacuna: em 14/08 foram 500 "ausentes" que eram historico
que a v1 decidiu nao integrar.
A materia e o que diz se aquela tramitacao pertence a algo que o hub deveria ter
integrado. Sem ela a conferencia nao tem como distinguir lacuna de fora-de-escopo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implementa o lado SAPL do refinamento da reconciliacao.
INVENTARIO — GET /api/integracao/reconciliacao/?id_gt=&tramitacao_id_gt=
devolve apenas IDS de proposicoes e tramitacoes acima do corte, com a flag
`truncado` avisando quando a faixa encheu. E lista de conferencia, nao
segunda via dos dados: o hub compara com o que conhece e descobre o que
ficou de fora. Corte por ID porque Proposicao NAO tem campo de criacao — as
datas que existem sao de estado (envio, recebimento, devolucao) e nenhuma
responde "quando apareceu". Mesmo filtro dos polls (cancelado=False), senao
a reconciliacao apontaria canceladas como ausentes para sempre.
KEYSET (data, id) nos polls por data — corrige o travamento do refinamento
§1.1: com cursor so de data e >=, uma pagina inteira de registros com o
MESMO timestamp devolvia sempre o mesmo cursor, ele nao avancava e a fonte
relia a mesma pagina para sempre, sem erro e sem nunca progredir. Agora
id_gt desempata dentro do instante.
TESTES: 9 novos (inventario + o cenario exato do travamento). Corrigidos
tambem tres defeitos das fixtures existentes, que nunca haviam rodado:
Token.objects.create colidia com o token que sapl/api/signals.py:8 cria no
post_save; TipoProposicao exige content_type; e Tramitacao sem status
quebrava a asercao. Resultado: 25 de 29 passam.
Os 4 que faltam sao de recepcao e falham por problema interno do
sapl.rules em banco de teste novo (ContentType matching query does not
exist), NAO por este diff — na versao da dev, sem estas mudancas, o mesmo
arquivo da 10 erros. O caminho de recepcao esta provado em producao
(proposicao 1071, criada pela ida em 14/08).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dois achados do teste manual de integracao (13/08, ambiente real):
1. select_related('materia_gerada') estourava FieldError — o campo NAO
existe no modelo: o bloco `materia_gerada = models.ForeignKey(...)` do
materia/models.py esta DENTRO de uma docstring (codigo morto). O vinculo
real e a generic FK conteudo_gerado_related (content_type + object_id),
que aponta para MateriaLegislativa OU DocumentoAcessorio — so a materia
interessa ao contrato. Sem isso, ProtocoloGerado nunca sairia.
2. O commit do autor_nome (ebf0fac) ficou fora do merge do PR #4 e o campo
sumiu do poll. Sem ele o acervo perde o nome do autor nao mapeado, que e
a regra do refinamento do historico §3.2. Reaplicado.
Verificado no ambiente real: poll devolve as proposicoes do acervo com
autor_nome e rascunho corretos.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
O ProposicaoCadastrada/ProtocoloGerado do contrato pedem descricao (e sigla,
na materia) do tipo; id sozinho obrigaria o hub a segunda consulta.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Componente A da spec (POST /api/integracao/proposicoes/): TokenAuthentication
com permissao propria, criacao pelo ProposicaoForm com autor fixado na
instancia antes do save (a numeracao usa a sequencia do autor), proposicao
nasce rascunho, dedupe por EventoRecebido (reentrega devolve 200 com a
proposicao existente), throttle auto-contido.
Componente B pelo fallback nomeado na spec §4: o get_queryset do
_ProposicaoViewSet nao expoe rascunho ao usuario de integracao, entao os
cinco polls (cadastradas/enviadas/recebidas/devolvidas por cursor proprio e
tramitacoes insert-only) vivem no app isolado, com ordenacao estavel
(data, id) para o cursor do hub.
Toque no core: duas linhas (INSTALLED_APPS e include no urls) — custo de
rebase contra o Interlegis proximo de zero, principio 1 da spec.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Evita depender de alguém lembrar de marcar a caixa em Tabelas Auxiliares
depois do deploy: a migration de dados marca dispensa_protocolo no tipo de
proposição "Ofício" que já existir no banco.
A comparação normaliza acentos, espaços e caixa, porque a descrição é digitada
em cada Casa e aparece como "Ofício", "OFICIO" ou "oficio". Casas que não têm
esse tipo cadastrado não são afetadas.
A migration é reversível: o reverse desmarca os mesmos tipos.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ofícios são documentos de uso próprio do gabinete do vereador e não precisam
de validação da Casa, mas hoje caem na fila de Proposições Pendentes como
qualquer outro tipo — a fila é definida apenas por data_envio/data_recebimento/
data_devolucao, sem considerar o tipo. O protocolo vinha devolvendo esses
ofícios na mão.
Adiciona TipoProposicao.dispensa_protocolo, configurável em Tabelas Auxiliares
-> Tipo de Proposição, em vez de fixar a regra no tipo "Ofício". Para os tipos
marcados:
- As ações 'send' e 'send_setor' são recusadas, então data_envio nunca é
gravada e a proposição não entra na fila do Protocolo nem do Setor
Legislativo.
- O botão "Enviar Proposição" dá lugar a um selo explicativo no detalhe.
- A listagem do vereador ganha o status "Documento de Gabinete" e o filtro
correspondente; esses documentos saem da contagem de "em elaboração".
A visibilidade já é resolvida pelo container_field='autor__operadores' do
ProposicaoCrud: a proposição só é acessível ao gabinete do autor.
Proposições já existentes não são tocadas — as que estão enviadas, devolvidas
ou já incorporadas seguem com o status atual.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Customização para o Procurador Jurídico da Câmara de Franco da Rocha,
identificado pelo grupo "Operador de Norma Jurídica" (SGVP_GROUP_NORMA):
- Tela inicial exibe somente o card "Matérias Legislativas".
- Documento Acessório já abre com Tipo="Parecer Jurídico", Nome="Aprovado"
e Data=data atual. Os campos seguem editáveis.
Adiciona o helper sapl.rules.is_procurador_juridico, usado pelas duas
funcionalidades para manter o critério de grupo em um único lugar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CLAUDE.md/AGENTS.md agora apontam para knowledge/AGENTS.md com regras
anti-alucinação explícitas (vale para Claude Code, Codex e Cursor):
não inventar regra/contrato, dizer quando não está documentado, citar o
doc governante, knowledge/ prevalece sobre doc local divergente.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Documentacao oficial em knowledge/ (submodule de docs-ia-projects, branch
main). Path knowledge/ e nao docs/ porque tres repositorios ja tem docs/
proprio ainda nao migrado.
Clone: git clone --recurse-submodules
Atualizar: git -C knowledge pull origin main && git add knowledge
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adiciona pagina onde o Presidente da Mesa Diretora pode visualizar e
assinar em lote, com um unico certificado A1, TODOS os documentos
acessorios do tipo "Despacho" ainda pendentes de assinatura digital
(filtro frouxo: tipo__descricao__icontains "despacho").
Reuso integral do backend ja existente:
- docacessorio_assinar_lote() em views_assinatura.py ja aceita PKs de
documentos de multiplas materias num unico POST.
- Modal de 4 passos (selecao -> certificado -> previa -> progresso ->
resumo) extraido de documentoacessorio_list.html para partial
reusavel e incluido nos dois templates (refactor mecanico, HTML/JS
byte-a-byte identico).
Acesso: restrito ao grupo SGVP_GROUP_PRESIDENTE_MESA (ou superuser
para depuracao); demais usuarios recebem 403. Atalhos pra tela
aparecem so quando usuario esta no grupo:
- "Pesquisar Materia Legislativa" (botao na linha de filtro de
assinatura)
- "Materias Pendentes de Assinatura" (botao no bloco de acoes)
Arquivos:
- sapl/materia/views.py: ListView DespachosPendentesLoteView nova +
flag is_presidente_mesa nos contextos das views existentes.
- sapl/materia/urls.py: rota /materia/despachos-pendentes-lote.
- sapl/templates/materia/assinatura_doc_lote_modal.html (novo): partial
com modal completo.
- sapl/templates/materia/despachos_pendentes_lote_list.html (novo):
tela do presidente.
- sapl/templates/materia/documentoacessorio_list.html: substitui modal
embedded por include do partial.
- sapl/templates/materia/materialegislativa_filter.html: atalho.
- sapl/templates/materia/materias_pendentes_assinatura_list.html: atalho.
A condição em materialegislativa_detail.html exigia numero_protocolo
para mostrar o bloco com botão Assinar PDF Digitalmente, Ver PDF
Assinado, Todos em PDF e Todos em ZIP. Como o template de listagem
(materialegislativa_filter.html) já mostra a tag Pendente de
Assinatura baseado apenas em texto_original (sem exigir protocolo),
havia inconsistência: a matéria aparecia como pendente na lista mas
ao abrir o detalhe o autor não tinha botão para assinar.
Remove a exigência de numero_protocolo da condição externa. Os botões
internos preservam suas condições próprias (is_autor/can_edit_materia,
not ja_assinou, etc).