fix(votes): popular vote_date a partir da API em vez do JSON quebrado#89
Merged
Conversation
Cards de votações na dashboard exibiam data errada (ex: "23/05/2026" pra votações de 2020). O endpoint /roll-call-votes/ extraía date_vote de proposition.details.decisao_destino.Decisao.Data, estrutura que só existe em ~3% dos votos do Senado e nunca para Câmara — então a UI caía pro created_at (dia da ingestão). Cobertura medida: 0 de 221.217 votos da Câmara tinham data extraível; apenas 2.157 de 70.110 do Senado (3%). Total: 0.74% dos votos com data correta. Solução: - Migration adiciona coluna roll_call_votes.vote_date (DATE, nullable, com índice) — em ambos os models (api/ e mamute_scrappers/) - Crawler Câmara já parseava dataHoraRegistro no payload (linha 349) mas não persistia: agora _upsert_roll_call_vote grava vote_date - Crawler Senado análogo: parseava dataSessao no payload (linha 242), agora persiste via session_dt.date() - Endpoint usa vote.vote_date direto; mantém fallback temporário pro extrator legado pros votos pré-PR ainda sem vote_date populado - Script orquestrador backfill_vote_dates: agrupa votos pendentes por link (cada link = 1 votação = N votos), faz uma chamada HTTP por votação e UPDATE em lote. Padrão idêntico aos outros backfills: state file, flock, --chunks-per-run, --status, auto-encerra quando esvazia - Cron horário (:55, fora de conflito com os outros) + @reboot burst, para resilência a restart de container (mesma estratégia da PR #88) - Tests: endpoint (column vs JSON fallback), parse dos crawlers (dataHoraRegistro/dataSessao no payload), helpers do orquestrador (parse_date, scan_for_date, dispatch por host) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problema
Cards de votações na dashboard exibiam datas erradas (ex: "23/05/2026" pra votações de 2020). Causa: o endpoint
/roll-call-votes/extraíadate_votedeproposition.details.decisao_destino.Decisao.Data— estrutura JSON que só existe em ~3% dos votos do Senado e nunca para Câmara — então a UI caía procreated_at(Timeline.tsx:128:v.date_vote?.slice(0, 10) ?? v.created_at?.slice(0, 10)), exibindo o dia da ingestão.Cobertura medida em prod (Jun/2026):
Solução
Trazer a fonte de verdade pra uma coluna dedicada (
vote_date DATE), populada pelo crawler na ingestão.Mudanças
7c91a3e2f4d8_add_vote_date_to_roll_call_votes.py: adicionavote_date DATE NULL+ índice emroll_call_votesapi/db/models/roll_call_votes.pyemamute_scrappers/db/models/roll_call_votes.py): novo campodataHoraRegistrono payload (linha 349 antes do PR), mas o upsert não persistia. Agora persiste em_upsert_roll_call_votedataSessaojá no payload, agora persistido via.date()api/routers/roll_call_votes.py: preferevote.vote_date; mantém fallback (_extract_date_vote_legacy) só pros votos pré-PR aguardando backfill. Removeremos o fallback em PR posterior, quando cobertura chegar a 100%mamute_scrappers/scripts/backfill_vote_dates.py: orquestrador do backfill histórico. Agrupa votos pendentes porlink(cada link representa 1 votação = N votos, então ~5-10k chamadas HTTP cobrem todos os 291k votos), faz GET por votação, UPDATE em lote. Padrão idêntico aos outros backfills (state file,flock,--chunks-per-run,--status, auto-encerra quando termina)mamute_scrappers/docker/scrappers.cron): entry horária:55+@rebootburst — resiliente a restart de container (mesma estratégia da PR feat(scrappers): bursts de backfill resilientes a restart de container #88)Testes
api/tests/test_roll_call_votes_date.py: endpoint usa coluna quando populada; cai no fallback quando NULL; helpers do extrator legadomamute_scrappers/tests/test_roll_call_votes_vote_date_parse.py: parse dos payloads (CâmaradataHoraRegistro, SenadodataSessaocom variações de capitalização)mamute_scrappers/tests/test_backfill_vote_dates.py: helpers puros do orquestrador (_parse_date,_scan_for_date,_resolve_fetcher)Resultado local:
pytest api/tests/ -v→ 27 passed (todos verdes, incluindo otest_project_dashboard_activityque precisou de update do schema inline).Plano de deploy
alembic upgrade headautomaticamente (PR ci(deploy-prd): aplica alembic upgrade head em prod apos rebuild #79 já cobre isso)vote_datenas próximas execuções (rolam de 3 em 3 horas)@rebootburst dobackfill_vote_datesdispara assim que o container reinicia (~30s pós-boot); o cron:55mantém ritmo horário caso o burst pare antes de zerarvote_dateé populado, o fallback legado vai sendo dispensado naturalmente. Quando cobertura ≈ 100%, abre-se PR de cleanup removendo_extract_date_vote_legacyTest plan
alembic upgrade headrodou no deploy (esperar a coluna no DB)camara-roll-call-votesno próximo run populavote_dateem novos votossenado-roll-call-votesbackfill_vote_dates --statusretorna progresso plausível pós-deployvote_datecorreto (não mais ocreated_at)SELECT COUNT(*) FILTER (WHERE vote_date IS NOT NULL) * 100.0 / COUNT(*) FROM roll_call_votes)🤖 Generated with Claude Code