← Todos os projetos

Como Vota: como o Congresso vota, em português claro

Transparência legislativa para a Câmara dos Deputados e o Senado Federal: cada proposição com resumo para leigos e caminho provável até a aprovação, e cada deputado e senador avaliado em presença, fidelidade partidária e alinhamento com o governo, sempre comparado à mediana dos colegas.

comovota.vmarcial.com.br ↗
  • computação
  • dados
  • civic tech

Site: comovota.vmarcial.com.br

A maioria dos brasileiros não lembra em quem votou para deputado ou senador, muito menos sabe como essa pessoa tem votado desde então. Os portais de dados abertos das duas Casas publicam tudo, mas em JSON, XML e PDFs digitalizados escritos em juridiquês. O Como Vota transforma isso em algo que um eleitor comum consegue ler.

O que o site faz

Proposições. Todo projeto de lei, proposta de emenda à Constituição, medida provisória e projeto de decreto legislativo das duas Casas, com:

  • um resumo para leigos de até três parágrafos (o que muda na prática, quem é afetado e em que ponto a proposta está), além de uma versão de uma linha;
  • etiquetas de assunto escolhidas de uma lista fixa de 28 temas, marcadas como "oficial" (classificação da própria Casa) ou "leitura do texto";
  • todas as leis, códigos e artigos da Constituição citados no texto, normalizados e com link para o portal de legislação ou para a página da proposição citada dentro do próprio site;
  • o texto integral oficial renderizado na página por um proxy de PDF, ao lado da linha do tempo completa da tramitação;
  • um painel de "próximos passos": o estágio atual, o caminho constitucional que falta percorrer e uma perspectiva de aprovação.

Votações. Cada votação nominal com os totais, a orientação formal de cada liderança partidária e do governo, e o voto individual de cada parlamentar.

Parlamentares. Um perfil por deputado e senador com mandatos, histórico de votos e estatísticas por legislatura: presença, fidelidade partidária, adesão à orientação do partido, adesão à orientação do governo e produção legislativa. Cada número aparece ao lado da mediana da Casa e da mediana do próprio partido, com o percentil do parlamentar, para que "82% de presença" tenha significado em vez de ser um número solto.

Tudo o que é calculado ou gerado está documentado em uma página pública de metodologia, para que o leitor consiga distinguir fato registrado de regra aplicada e de interpretação automática.

Arquitetura

O sistema é um pacote Python implantado como cinco serviços na Railway, todos construídos a partir de um único Dockerfile, mais um Postgres 16 e um volume persistente para o cache de PDFs.

| Serviço | Papel | | --- | --- | | web | API JSON em FastAPI sob /api, proxy de PDF e a SPA compilada servida como arquivos estáticos | | ingest-camara | Cron de hora em hora que esvazia a fila de jobs da Câmara (API REST e CSVs anuais) | | ingest-senado | Cron de hora em hora que esvazia a fila de jobs da API v3 do Senado | | enrich | A cada duas horas: extrai textos, coleta lotes concluídos e envia novos lotes ao Claude | | stats | Recálculo noturno das estatísticas de cada parlamentar e dos grupos de comparação |

Ingestão. É uma fila de jobs persistida no Postgres. O planejamento insere um job por par (tipo, chave), por exemplo um por ano de proposições da Câmara ou um por mês de votações do Senado, com prioridades que favorecem a legislatura atual. Os workers esvaziam a fila em fatias de uma hora, respeitando limites de requisições por fonte, repetem falhas com backoff exponencial e deixam os jobs que falharam de vez visíveis no endpoint de saúde. Rodar o planejamento de novo é idempotente, e é isso que torna viável uma carga histórica desde 1991 espalhada por muitas execuções curtas de cron. Cada Casa expõe seus dados de um jeito bem diferente (a Câmara pagina, o Senado devolve conjuntos inteiros), então cada uma tem seu próprio adaptador alimentando um esquema unificado.

Enriquecimento. Usa o Claude Sonnet 5 pela Message Batches API. O modelo recebe o texto integral extraído e um bloco de contexto (ementa, situação atual, últimas tramitações, votações, autores e assuntos oficiais) e devolve JSON estruturado, validado contra um esquema. Duas decisões de projeto mantêm o processo honesto e barato:

  • Um teto diário de gasto, com as proposições enfileiradas por relevância: primeiro as votadas nominalmente nos últimos 90 dias, depois as já votadas, depois as apresentadas recentemente, e o restante por último. Documentos digitalizados sem texto extraível são enviados como imagem apenas até um limite de páginas e de tamanho.
  • Um caminho separado, sob demanda. Quando um visitante abre uma proposição recém-votada que o pipeline em lote ainda não alcançou, a API gera um resumo curto só a partir da ementa, guarda-o sob sua própria versão de prompt e o serve apenas até o resultado completo do lote chegar. Falhas entram em espera e desistem depois de algumas tentativas, e um teto diário limita o custo.

Cada resumo guarda o modelo e a versão do prompt que o produziu, então todo o acervo pode ser refeito quando a metodologia mudar.

O que o modelo não decide. O estágio atual e o caminho restante são calculados por regras fixas derivadas da Constituição e dos regimentos internos das duas Casas: projetos de lei ordinária, projetos de lei complementar (maioria absoluta nos dois Plenários), propostas de emenda à Constituição (dois turnos com três quintos, sem sanção presidencial), medidas provisórias (com os prazos constitucionais de 45, 60 e 120 dias, suspensos no recesso), e projetos de decreto legislativo e de resolução, cada um com seu próprio caminho. Regime de urgência e vetos alteram o percurso. A leitura do modelo aparece apenas como justificativa complementar, sempre identificada como tal. As citações de leis também vêm primeiro de expressões regulares que reconhecem as formas canônicas de referência legal brasileira e convertem códigos citados pelo nome para a lei correspondente; a lista do modelo passa pelo mesmo normalizador.

As estatísticas

A parte interessante da análise é decidir o que conta. Votações secretas são exibidas, mas ficam fora de todas as métricas. Votações simbólicas, sem registro individual, ficam fora porque não há voto a avaliar. Um parlamentar só é avaliado nas votações realizadas enquanto estava de fato em exercício, descontando licenças e ausências oficiais, então o suplente é avaliado no próprio período e o titular licenciado não é cobrado pelas votações em que não estava.

As taxas de alinhamento usam apenas sim, não e obstrução. A obstrução é tratada como posição própria: quando a orientação de referência foi obstruir, obstruir conta como concordância; quando foi sim ou não, obstruir conta como discordância.

  • Fidelidade partidária compara cada voto com a maioria estrita dos colegas do próprio partido naquela votação, excluindo o parlamentar, exigindo ao menos cinco colegas e usando o partido a que ele pertencia no dia da votação.
  • Orientação do partido compara com a orientação formal da liderança, ou do bloco quando o partido não orientou sozinho. Bancada "liberada" fica de fora.
  • Orientação do governo usa a orientação oficial da liderança do governo na Câmara. No Senado esse registro só existe a partir do fim de 2019 e tem falhas, então duas aproximações identificadas preenchem as lacunas: o voto do Líder do Governo no Senado e, depois, a maioria estrita dos senadores dos partidos da base, com ao menos dez votos. Cada perfil informa quantos votos vieram de cada fonte, e um indicador mais rígido, "vota com o governo", exclui totalmente a aproximação por coalizão.
  • Produção legislativa conta proposições de conteúdo como primeiro autor e como coautor, normalizadas por ano de mandato efetivo com um piso para que quem tomou posse no mês passado não lidere o ranking.

Os grupos de comparação exigem no mínimo 20 votações elegíveis (ou 90 dias de mandato, para a produção), o que evita que mandatos muito curtos distorçam as medianas.

Stack

Python 3.12, FastAPI, SQLAlchemy 2 e Alembic sobre Postgres 16; httpx com tenacity nos clientes das fontes; pypdf para extração de texto; o SDK da Anthropic com a Batches API para o enriquecimento. O frontend é uma single-page app em JavaScript puro, sem dependências, compilada com Vite: roteador próprio, componentes em template literals e medidores em SVG inline. A API adiciona ETags fracas e cabeçalhos de cache para que a SPA e qualquer CDN na frente possam fazer requisições condicionais. A infraestrutura é declarada como código com o SDK da Railway, e a suíte de testes roda contra um Postgres embutido, sem precisar de rede nem de banco em execução.