Skip to content

fix: br_me_caged não detecta atualizações do CAGED - #1760

Closed
Winzen wants to merge 23 commits into
mainfrom
fix/br_me_caged_poll_migration
Closed

Winzen wants to merge 23 commits into
mainfrom
fix/br_me_caged_poll_migration

Conversation

@Winzen

@Winzen Winzen commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Contexto

br_me_caged__microdados_movimentacao estava reportando "Não há novas atualizações na fonte original" mesmo com a fonte (FTP ftp.mtps.gov.br/pdet/microdados/NOVO CAGED) já tendo publicado a competência de junho/2026 desde 29/07.

Causa raiz

O poll antigo (poll_source_for_update) compara a data da fonte contra Table.Update.latest — que não é a cobertura real dos dados, e sim o timestamp de quando a tabela foi materializada (bq.last_modified). Uma materialização anterior gravou Table.Update.latest = 2026-07-07, um timestamp de execução. Como a data da fonte é sempre representada pelo dia 1 do mês (2026-06-01), a comparação 2026-06-01 > 2026-07-07 é falsa — bloqueando a detecção mesmo com dado novo disponível. É o mesmo defeito arquitetural já corrigido no br_ms_cnes, migrando para o modelo de poll novo (pipelines/utils/metadata/poll.py).

O que muda

Os 3 flows do dataset (microdados_movimentacao, _fora_prazo, _excluida — compartilham _run_me_caged) passam a usar:

  • register_source_coverage_task + check_source_is_ahead_of_table_task antes do download (em vez de poll_source_for_update_task)
  • sync_table_coverage_task depois da materialização (em vez de register_table_materialization_task + commit_source_update_task)

sync_table_coverage_task grava Table.Update.latest com a cobertura real lida do BigQuery (bq.read_max_date), não com o horário de execução — eliminando a causa do travamento.

Observação: Table.Update.latest da tabela microdados_movimentacao está hoje contaminado com 2026-07-07 (resíduo do poll antigo) e não vai se autocorrigir sem uma materialização bem-sucedida — precisa de correção manual ou de um force_run=True antes que o gate novo funcione corretamente.

… vs timestamp de execução)

O poll antigo comparava a data publicada pela fonte (FTP) contra
Table.Update.latest, que é o timestamp de quando a tabela foi
materializada (bq.last_modified), não a competência coberta pelos
dados. Isso trava a detecção de atualização sempre que uma
materialização anterior grava um timestamp de execução "adiantado"
em relação ao dia-1 do mês publicado pela fonte seguinte — foi o que
aconteceu com microdados_movimentacao: Table.Update ficou em
2026-07-07 e bloqueou a detecção de junho/2026, já disponível no FTP
desde 29/07.

Migra os 3 flows do dataset (compartilham _run_me_caged) para o
modelo de poll novo (pipelines/utils/metadata/poll.py), já usado pelo
CNES: register_source_coverage_task + check_source_is_ahead_of_table_task
antes do download, sync_table_coverage_task depois da materialização
— que grava Table.Update com a cobertura real lida do BigQuery, não
com o horário de execução.
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The CAGED flow registers source coverage, checks source freshness against table coverage, and synchronizes table coverage. It removes direct source polling, table materialization registration, and the conditional source update commit.

Changes

CAGED coverage flow

Layer / File(s) Summary
Register and check source coverage
pipelines/datasets/br_me_caged/flows.py
The flow registers the latest source coverage. When force_run is false, it runs only if the source is ahead of the table.
Synchronize table coverage
pipelines/datasets/br_me_caged/flows.py
The flow synchronizes table coverage with the existing coverage definition and production BigQuery project. It removes the conditional source update commit.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • basedosdados/pipelines#1749: Addresses the polling bug through source-coverage registration and table-coverage synchronization.

Possibly related PRs

Suggested labels: check-metadata

Suggested reviewers: laura-l-amaral

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed O título descreve claramente a correção do problema de detecção de atualizações do CAGED, mas não usa o prefixo [Bugfix] exigido pelo template.
Description check ✅ Passed A descrição explica o contexto, a causa raiz e as alterações técnicas, mas não documenta testes, riscos, rollback e dependências conforme o template.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/br_me_caged_poll_migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Winzen Winzen changed the title fix(br_me_caged): migra para o poll novo (cobertura vs cobertura) fix: br_me_caged não detecta atualizações do CAGED Aug 6, 2026
@Winzen Winzen self-assigned this Aug 6, 2026
@Winzen Winzen added the deploy-flow [PR] Dispara deploy dos flows alterados no work pool basedosdados-dev (Prefect 3 staging) label Aug 6, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pipelines/datasets/br_me_caged/flows.py`:
- Around line 48-60: Before enabling the scheduled flow, repair the production
Table.Update.latest metadata that is stale or contaminated: either add the
required correction to this flow before the source-ahead gate, or perform a
manual recovery run with force_run=True and update_metadata=True. Ensure the
correction occurs before normal scheduled runs can return early, while
preserving the existing materialization and coverage behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1fb89040-9f0d-4ef1-b71a-d04f783680df

📥 Commits

Reviewing files that changed from the base of the PR and between 2f70710 and 56fbe93.

📒 Files selected for processing (1)
  • pipelines/datasets/br_me_caged/flows.py

Comment thread pipelines/datasets/br_me_caged/flows.py
@Winzen Winzen added deploy-flow [PR] Dispara deploy dos flows alterados no work pool basedosdados-dev (Prefect 3 staging) and removed deploy-flow [PR] Dispara deploy dos flows alterados no work pool basedosdados-dev (Prefect 3 staging) labels Aug 6, 2026
Marca as 3 chamadas de metadata (register_source_coverage_task,
check_source_is_ahead_of_table_task, sync_table_coverage_task) que
hoje apontam direto para env="prod", para facilitar testar a
migração do poll novo contra o backend de dev antes de tocar nos
registros de produção.
@laura-l-amaral laura-l-amaral linked an issue Aug 6, 2026 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot mentioned this pull request Aug 7, 2026
1 task
@coderabbitai coderabbitai Bot mentioned this pull request Aug 8, 2026
4 tasks
@Winzen

Winzen commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

Validação em produção (2026-08-09)

Rodei os 3 flows do dataset a partir desta branch para validar a correção antes do merge:

Flow Run Resultado
microdados_movimentacao Sleek-Bombay Table.Update atualizado para a cobertura 2026-06-01
microdados_movimentacao_excluida Ergonomic-Coyote Fonte publicou cobertura nova: 2026-06-01 → materializou → Table.Update atualizado para a cobertura 2026-06-01
microdados_movimentacao_fora_prazo Generic-Skua Fonte publicou cobertura nova: 2026-06-01 → materializou → Table.Update atualizado para a cobertura 2026-06-01

Conferido direto no BigQuery (fora do que o próprio flow logou) — junho/2026 chegou certo nas 3 tabelas, sem duplicação:

Tabela Linhas em 2026-06 numRows antes → depois
microdados_movimentacao 4.295.101 275.291.553 → 279.586.654
microdados_movimentacao_fora_prazo 65.573 8.609.944 → 8.675.517
microdados_movimentacao_excluida 8.719 607.497 → 616.216

Table.Update.latest das 3 tabelas também foi corrigido manualmente antes do teste (estava contaminado com 2026-07-07, resíduo do poll antigo) — sem isso o gate não teria passado nem nesta branch.

Pendência: essa validação rodou a partir desta branch, não do deploy normal via main. O cron agendado em produção ainda aponta para o código antigo até este PR ser mergeado — o merge continua necessário para a correção valer nas próximas execuções automáticas.

Winzen added a commit that referenced this pull request Aug 11, 2026
… pro poll.py)

Teste da abordagem alternativa ao PR #1760 (migração completa pro
poll.py): br_me_caged ainda usa poll_source_for_update_task, mas agora
com compare_against="coverage" em vez do default antigo
(Table.Update.latest, o campo contaminado que causou o bug original).

register_table_materialization_task já atualiza Coverage.DateTimeRange
a partir do BigQuery corretamente — isso nunca foi o problema. Só a
comparação de leitura estava errada. Se compare_against="coverage"
sozinho resolver, não precisamos da migração inteira pro poll.py.

Afeta os 3 flows (microdados_movimentacao, _fora_prazo, _excluida) via
_run_me_caged compartilhado. Teste-piloto: microdados_movimentacao_fora_prazo.
@Winzen Winzen removed the deploy-flow [PR] Dispara deploy dos flows alterados no work pool basedosdados-dev (Prefect 3 staging) label Aug 12, 2026
Winzen added a commit that referenced this pull request Aug 12, 2026
Fecha a causa raiz sistêmica por trás da issue #1781: poll_source_for_update
sempre comparava a fonte contra Table.Update.latest (timestamp de execução),
nunca contra Coverage.DateTimeRange (cobertura real) — um parâmetro que
existia no Prefect 0 (date_type) e se perdeu silenciosamente na migração
pro Prefect 3.

- Restaura a escolha como compare_against="coverage"|"table_update" em
  poll_source_for_update/poll_source_for_update_task, com validação
  (ValueError em valor inválido) e logging das datas comparadas.
- MetadataClient.get_coverage_max_date(): novo método de leitura de
  Coverage.DateTimeRange.
- Aplicado explicitamente nos 32 flows que usam poll_source_for_update_task,
  auditados um a um contra o comportamento do Prefect 0 (worktree
  pré-migração); default trocado de "table_update" para "coverage" depois
  que todos os callers passaram a ser explícitos.
- Corrige br_me_cnpj/simples e br_rf_cnpj/simples,dicionario: tabelas
  NonHistorical não têm Coverage.DateTimeRange, então precisam de
  compare_against="table_update" especificamente.
- commit_source_update_task movido para logo após o poll confirmar dado
  novo (antes de baixar/materializar), em vez de só no fim do flow — se o
  flow falhar no meio, o RawDataSource.Update ainda reflete que a fonte
  publicou. Ganhou os parâmetros update_metadata/materialize_after_dump
  (default True) para decidir sozinha se grava, evitando repetir o mesmo
  guard em ~25 flows. register_table_materialization_task continua no fim,
  sem mudança.
- Corrige o Pyrefly type check (quebrado por um PR não relacionado,
  onboarding do us_harvard_cbdb) adicionando o exclude correspondente.
- Testado ao vivo em produção nas 3 tabelas do br_me_caged (compare_against
  e o commit adiantado, confirmados via logs e BigQuery).

Relacionado: #1784 (consolidado nesta branch), #1760 (decisão em aberto,
compare_against="coverage" pode tornar a migração pro poll.py innecessária).
@Winzen

Winzen commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

Fechando este PR — o mesmo problema (poll comparando contra Table.Update.latest em vez da cobertura real) já foi resolvido pelo #1783, que acabou de ser mergeado, de um jeito mais simples: compare_against="coverage" faz o poll_source_for_update ler Coverage.DateTimeRange direto, sem precisar repropositar Table.Update (que este PR fazia via sync_table_coverage_task) nem introduzir o gate intermediário check_source_is_ahead_of_table_task.

Durante os testes finais do #1783 usando exatamente as tabelas do CAGED, achamos evidência ao vivo de que a abordagem deste PR é mais frágil: Table.Update.latest da tabela microdados_movimentacao_excluida estava contaminado com um timestamp de execução (2026-08-12) em vez de uma data de cobertura, bloqueando check_source_is_ahead_of_table_task de detectar novidade — porque Table.Update é um campo compartilhado, e qualquer código que ainda escreva nele com a semântica antiga (register_table_materialization_task, usado em ~30 outros flows) contamina de volta. Coverage.DateTimeRange não tem esse ponto de quebra.

br_me_caged já está usando compare_against="coverage" (aplicado direto no #1783), testado em produção nas 3 tabelas. Vou fechar este PR em favor disso.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[databug] br-me-caged

1 participant