basedosdados / basedosdados/pipelines

[bug] poll: a checagem lê horário no Table.Update e o flow fecha verde sem ingerir

Open
#1,749 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
49
Forks
22
Avg merge
1d 3h
Merged PRs (30d)
167

Description

O `check_source_is_ahead_of_table` decide se há o que materializar comparando a cobertura
publicada pela fonte com o `Table.Update.latest`. Nas tabelas que ainda não passaram uma vez
pelo modelo novo, esse campo guarda **horário de execução**, não cobertura — e horário de
2026-06 é sempre maior que a competência 2026-06-01. O flow encerra em `COMPLETED` sem
ingerir nada, e o log é a única pista.

Ele contém duas afirmações incompatíveis na mesma run (`br_ms_cnes__equipe`, 2026-08-03):

```
------- The year_month_to_parse (YYMM) is 2606 ← a tabela para em 2026-05
Fonte sem cobertura nova
Tabela CNES já cobre a fonte — encerrando ← a tabela cobre a fonte
```

Se a tabela cobrisse a fonte, o `check_files_to_parse` não teria derivado 2606 como a
competência a parsear. As duas linhas leem registros diferentes para a mesma pergunta:

| Passo | Lê | Resultado naquela run |
|---|---|---|
| `check_files_to_parse` (`crawler/datasus/tasks.py`) | `get_api_most_recent_date` → fim do `DateTimeRange` da cobertura | 2026-05, correto |
| `check_source_is_ahead_of_table` (`utils/metadata/poll.py`) | `Table.Update.latest` | 2026-06-17, horário da materialização |

## Não se corrige sozinho

O único ponto que troca esse valor por cobertura é o `sync_table_coverage`
(`utils/metadata/poll.py`), que roda **depois** da checagem — e ainda dentro de
`materialize_after_dump` e `update_metadata`. Para a checagem passar, o flow precisava ter
rodado; para rodar, a checagem precisava passar.

Em 2026-08-03 as 11 tabelas do CNES com cron foram destravadas à mão, escrevendo a cobertura
no `Table.Update.latest` via `create_update_update` em prod (registrado no
`pipelines/datasets/br_ms_cnes/README.md`). Depois disso a `equipe` rodou em dev e em prod e
o `sync_table_coverage` passou a manter o campo: `Table.Update atualizado para a cobertura
2026-06-01`. As outras 10 seguem no valor escrito à mão até o primeiro run de prod de cada
uma.

Ou seja: hoje o modelo novo exige um destravamento manual por tabela que não está em lugar
nenhum do código. Toda tabela nova, ou todo conjunto que adote o modelo, vai repetir isso.

## O mesmo defeito existe no poll antigo

O `poll_source_for_update` (`utils/metadata/register.py`) compara
`should_update_raw_source(api_latest=get_table_update_latest(...), source_max)`, e o
`register_table_materialization` grava nesse mesmo campo
`latest=bq.last_modified(dataset_id, table_id)` — outro horário. Os demais flows do repo,
que seguem nesse poll, comparam cobertura com horário do mesmo jeito. Ali o defeito é
latente: passa ou não por acidente, conforme o atraso de publicação da fonte.

Vale registrar o efeito colateral de diagnóstico: **um run que não ingere é indistinguível
de um saudável pelo estado do Prefect.** Os dois terminam em `COMPLETED`, e só o log ou a
cobertura no backend dizem qual é qual.

## Referências

- #1707 — modelo de poll novo, primeiro adotante CNES
- #1734 e #1740 — o formato do upload, onde o log apareceu
- `pipelines/utils/metadata/poll.py`, `pipelines/utils/metadata/register.py`
- `pipelines/datasets/br_ms_cnes/README.md`, seção "Modelo de poll (PR #1707)"

Contributor guide

Open the contributing guide

Research direction

Start with check_source_is_ahead_of_table and sync_table_coverage in pipelines/utils/metadata/poll.py, then trace poll_source_for_update and register_table_materialization in pipelines/utils/metadata/register.py. Compare these paths with check_files_to_parse in crawler/datasus/tasks.py and the CNES README. Done means polling uses the same coverage meaning throughout and does not silently skip ingestion because of an execution timestamp.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data-engineering
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.