Manutenção e atualização¶
Fluxo de trabalho¶
- Identificar o produto. Registrar categoria, subtipo, tabela física, período, situação preliminar/final e arquivo amostrado. Confirmar o dataset correspondente; não associar SIA/PA ao YAML de SIA/BI só pela categoria.
- Localizar a referência oficial. Priorizar leiaute/dicionário do órgão produtor para a edição do produto. Tabelas auxiliares oficiais sustentam domínios. Material secundário serve como pista e deve ser identificado como tal, sem receber a autoridade de uma fonte primária.
- Congelar a evidência. Registrar URL, órgão, título, edição, tamanho, SHA-256 e data da obtenção. Arquivos podem ficar em cache fora do Git; preservar uma cópia recuperável na infraestrutura do projeto quando existir um arquivo institucional autorizado. Uma URL com hash detecta alteração, mas não garante que a versão antiga continuará disponível.
- Extrair afirmações. Preencher descrição, domínio, formato e relações com página/seção. OCR ou busca de nomes gera candidatos para revisão, não confirmação semântica.
- Fazer a segunda checagem. Comparar a extração com o documento renderizado e conferir o vínculo com o leiaute/período do arquivo real. Registrar cada método e sua evidência. Comparar outra referência oficial aplicável quando disponível; uma inconsistência não deve ser resolvida por suposição.
- Revisar valores e estrutura. Comparar nomes, tipos e valores observados com a definição, guardando o arquivo/hash/recorte. Frequências observadas não completam um domínio documental nem provam vigência histórica.
- Validar e publicar uma edição. Validar contratos, referências, hashes, intervalos e cobertura; gerar docs/JSON; revisar o diff. Distribuir os metadados com a lib somente após passar pelos critérios abaixo.
“Double check” tem dois resultados independentes: transcrição conferida e aplicabilidade conferida. No exemplo SIM, o primeiro foi realizado e o segundo está pendente para os dados de 2023. Uma revisão por outra pessoa pode ser registrada com identidade própria; não inventar essa etapa quando não houve.
Quando atualizar¶
Rever o produto quando surgir documento com hash novo, campo novo/removido, tipo incompatível, código fora do domínio ou divergência relatada por usuário. Antes de cada publicação da lib, gerar o relatório de pendências e conferir as fontes dos produtos alterados. Como política inicial, revisar trimestralmente o índice de fontes de produtos ativos; o responsável pode ajustar a cadência por produto. Nenhuma automação periódica foi instalada por estes documentos.
Uma consulta que encontra os mesmos bytes atualiza last_checked_on da fonte,
não a data de revisão de cada afirmação. Novo hash cria nova revisão da
fonte e abre a revisão dos campos dependentes. Conservar o histórico anterior.
Critérios de validação para a integração¶
| Verificação | Resultado esperado |
|---|---|
| Contrato | JSON/YAML válido e versão suportada |
| Referências | IDs únicos; todos os IDs de fontes/domínios resolvidos |
| Evidência | Afirmação verificada com fonte oficial, localizador, responsável, método e data |
| Mudança editorial | Hash do valor checado coincide com o valor publicado |
| Identidade | Campo pertence ao produto e à edição corretos |
| Vigência | Sem ambiguidades silenciosas para o mesmo recorte |
| Domínio | Códigos string únicos, sem perda de zeros; desconhecidos preservados |
| Observação | Arquivo e hash identificados; diferenças explicitadas |
| Cobertura | Denominador por tabela/edição; campo ausente não desaparece do relatório |
| Compatibilidade | Decodificadores existentes e ingestão não mudam por edição bibliográfica |
| Distribuição | JSON, Arrow/Parquet e recursos no wheel conferidos |
Separar cobertura de descoberta, de descrição verificada, de códigos verificados e de aplicabilidade confirmada. Não somar menções textuais com campos validados. A contagem de ocorrências considera cada tabela; campos homônimos em tabelas diferentes não são deduplicados globalmente.
Falhas e conflitos¶
Quando não houver documentação, manter o campo com significado desconhecido e registrar onde se procurou e a data. “Não encontrado” não significa “não existe”. Em conflito, registrar as duas referências, as afirmações concorrentes e o recorte afetado; impedir interpretação automática nova até resolução. Não substituir o valor bruto por um palpite ou descartar códigos desconhecidos.
Versão do dicionário¶
Toda mudança no conteúdo de um dicionário — inclusive a saída de gerar_decode_cnv.py,
gerar_sinan.py, gerar_subconjuntos_sim.py e validar_fonte.py --accept — exige
trocar a x-version do dicionário por uma maior e rodar
uv run python scripts/metadados/travar_versoes.py, que registra o SHA-256 do conteúdo
da nova versão em src/omnisus/data/dicionarios/versoes.json. O teste
tests/unit/scripts/test_travar_versoes.py falha enquanto isso não é feito. O script
para se o conteúdo mudou sem trocar a x-version, se a nova versão é menor que uma já
travada ou se a x-version volta a uma versão anterior.
versoes.json só cresce. Um conflito nele quer dizer que duas mudanças reivindicaram a
mesma versão do mesmo dicionário: resolve-se trocando de novo a x-version e rodando o
script, nunca editando ou apagando entradas à mão. O script não percebe uma entrada
apagada e regerada; por isso, na revisão, recusar todo diff que remove ou altera uma
linha de versoes.json.
Regenerar os rótulos¶
Para os rótulos gerados de CNV do TabWin (method: cnv-parse), regenerar com:
uv run --locked python scripts/metadados/gerar_decode_cnv.py
Um campo ligado a um DBF relacionado (TabWin.pdf p. 88) também entra em campos,
com o membro .dbf, e é escrito com method: dbf-parse. largura (por dataset, por
campo) guarda só os códigos com esse número de caracteres: MOTERRO.dbf tem uma série de 4
caracteres com texto em CP850, que o gerador recusaria pelo byte C1, e os arquivos ER só
publicam a de 6.
Um arquivo publicado byte a byte em mais de um pacote (ou duas vezes no mesmo) fica
empacotado uma vez só. Os outros membros de membros não têm arquivo e dizem
"mesmo_que": "<chave do membro empacotado>"; cada um guarda sua fonte, seu membro e
seu sha256, e o gerador lê os bytes do membro nomeado e confere o hash contra o
sha256 próprio. O membro nomeado não pode ter mesmo_que.
def é sempre uma lista de DEF. Quando vários pacotes publicam os mesmos vínculos, a
lista tem um DEF por pacote, o primeiro sendo o que já servia de base (é o caso de
sih_aih_reduzida_1992_2007, com os três RD.DEF das eras); um campo ligado a DBF aceita
um DEF só, porque a coluna de descrição é lida de um DEF. Para cada DEF da lista o
gerador procura o membro na mesma posição relativa à pasta do DEF, exige o mesmo
sha256 do membro de campos, confere que aquele DEF liga o campo a ele na posição 1
e escreve uma evidência por pacote, na ordem da lista; checked_at é a data de coleta
mais recente entre essas fontes.
Rodar de novo não muda nada quando os vínculos e os membros empacotados não
mudaram; em revisão, usar --check, que falha se algum dicionário mudaria. Um
arquivo TabWin republicado entra no registro com um novo id e novos membros —
não sobrescreve o registro existente. vinculos.json
(src/omnisus/data/dicionarios/sources/cnv/vinculos.json) é o único lugar
onde o CNV de um campo é escolhido; o gerador não decide isso sozinho.
O gerador só escreve campo sem claim /field/codes; o mapa anterior que discorda
fica no issue cnv-difere-do-mapa-anterior. Uma claim de códigos já existente nunca
é descartada: se o método não é cnv-parse (por exemplo, rótulos lidos de uma página),
o gerador para e nomeia dataset, campo, método e evidência; se é cnv-parse e o CNV
dá o mesmo mapa, só evidence e checked_at podem mudar: o gerador é dono dos dois e
reescreve uma edição à mão (as outras chaves da claim ficam), então --check falha
nela. Essa reescrita muda o conteúdo do dicionário e por isso pede subir a x-version
e rodar scripts/metadados/travar_versoes.py (o teste da trava cobra); se o mapa
difere, ele para e lista os códigos que mudaram.
Nos dois casos de parada, a mudança é revista e escrita à mão.
Um conflicting de cnv-parse cujo mapa anterior não tinha fonte também se resolve à
mão: a claim passa a verified_in_source e o issue cnv-difere-do-mapa-anterior passa a
resolved, guardando o texto do mapa anterior.
Os campos de sim_obitos_infantis, sim_obitos_maternos e sim_obitos_externos são os
de sim_obitos (os registros são do DO). Depois de mudar sim_obitos.yaml,
regenerar com uv run --locked python scripts/metadados/gerar_subconjuntos_sim.py; o teste
tests/unit/scripts/test_gerar_subconjuntos_sim.py falha enquanto não se regenera.
Para os campos comuns da Notificação Individual do SINAN (method: page-read),
escritos uma vez em scripts/metadados/sinan_bloco_comum.yaml, regenerar com:
uv run --locked python scripts/metadados/gerar_sinan.py
Rodar de novo não muda nada quando o bloco comum não mudou; em revisão, usar
--check, que falha se algum dicionário SINAN mudaria. Um código só entra em
x-decode depois de entrar na lista codigos de uma entrada de fontes, com a
página do dicionário oficial que o cita ou o CNV empacotado de TAB_SINANNET que o
lista; o gerador para se a união dos codigos de todas as fontes de um campo não for
exatamente o conjunto de chaves de x-decode, ou se um código citado por uma fonte
com membro não estiver naquele CNV. Um campo do bloco nunca é também um campo de
campos em sources/cnv/vinculos.json: cada campo SINAN tem exatamente uma fonte de
decodificação, a página ou o CNV, nunca as duas.
Numa entrada de agravo.<dataset>, o campo substitui, só naquele dicionário, a entrada
de comum de mesmo nome (é o caso de sinan_tuberculose.doenca_tra). Os dois geradores
têm campos disjuntos e podem rodar em qualquer ordem, mas mover um campo de um para o
outro é barrado nos dois sentidos. Do bloco comum para o CNV: se o campo sair do bloco (ou
de agravo.<dataset>) e entrar em campos de vinculos.json sem apagar a claim
/field/codes antiga à mão, os dois geradores param —
gerar_decode_cnv.regenerate recusa uma claim cujo method não é cnv-parse ("review
it by hand before the CNV map may replace it"), e gerar_sinan.generate recusa uma
claim page-read sem entrada no bloco. Do CNV para o bloco comum, também: gerar_sinan.
generate recusa escrever um campo do bloco cuja claim atual tem method: cnv-parse
("review it by hand before the block may replace it"). Nos dois sentidos, quem move o
campo apaga a claim antiga à mão e confere o campo regenerado.