O pipeline de dados
O Futuros não consulta APIs ao vivo quando alguém abre uma página. Todo o corpus é ingerido, baked e congelado como JSON estático antes do deploy; a SPA só lê arquivos. Isso torna a plataforma rápida, cacheável, capaz de operar offline, e, sobretudo, auditável: cada cifra que você vê foi verificada em tempo de build contra seu registro de fonte. Este pipeline serve diretamente ao Pilar 1 — Fundo Fiduciário de Dados: um corpus com proveniência e licença limpa é o único ativo que um modelo regional não pode copiar.
GCF: apenas anos civis completos; o ano em curso não é publicado como dado comparável.
O registro de fontes
Cada fonte externa é um SourceRecord declarado em scripts/sources/registry/. Ele define de onde sai o dado e sob quais regras pode ser publicado:
AdapterEngine: o tipo de conector:series,bulk,sdmx,ckan,ocds,event,entity,microdata,provideroumeta. Cada API externa tem um único adaptador emadapters.ts(WHO GHO, UNESCO UIS, OpenAlex, Climate Watch, UN SDG, UNHCR, OWID, IMF DataMapper, SDMX/DBnomics genérico…). As ondas posteriores vivem emscripts/sources/gap/(um arquivo por fonte). A onda F (wave-f/+src/lib/gap-sources-f/) é o passe de granularidade plena: emaciação JME, matrícula terciária UIS, nutrição DHS, espaço cívico CIVICUS, preenchimento Ember/IRENA, e sondas de lacuna honesta (RICYT, ILIA/GIRAI/GDB, INE.Stat saúde/inovação do Chile, ENDI) que re-verificam e devolvem[]. Atualização:scripts/refresh-wave-f.ts. A onda H (wave-h/+src/lib/gap-sources-h/) usa o mesmo corte. Sua primeira fonte é o registro de empréstimos soberanos do China Development Bank e do Export-Import Bank of China compilado por Myers e Gallagher (Boston University Global Development Policy Center e Inter-American Dialogue): estoque de compromissos, não dívida pendente, com direção neutra, então fica fora do índice composto. A segunda fonte é o NOAA NCEI IBTrACS v04r01: ciclones tropicais únicos por temporada completa desde 1980, atribuídos aos 25 países com as costas do Natural Earth. É uma contagem de ameaça e fica neutra no índice composto. A terceira fonte são as estatísticas de turismo receptivo da ONU Turismo (chegadas e receitas, parceiro Mundo): níveis absolutos que crescem com o tamanho do país, então ficam neutros no índice composto, e o país cujo dado mais recente fica fora do limiar de vigência é omitido em vez de imputado. A quarta fonte são as estatísticas do BIS (preços reais de imóveis residenciais, crédito total e às famílias como % do PIB, hiato crédito/PIB): só publicam seis dos 25 países (Argentina, Brasil, Chile, Colômbia, México e Peru; Argentina sem preços de imóveis, Peru sem crédito), o resto é omitido em vez de imputado, e ficam neutros no índice composto. A quinta fonte é a IATI via d-portal (Secretariado da IATI): desembolsos e compromissos em USD correntes por país receptor e ano civil completo, ponderados pelo percentual de país declarado em cada atividade, mais uma série de desembolsos que exclui nove bancos multilaterais de desenvolvimento; fluxos intermediados podem ser contados duas vezes e a cobertura de publicadores cresceu com o tempo; o ano corrente é omitido, um ano ausente é uma lacuna e não um zero; ficam neutros no índice composto.LicensePosture:kind/redistribute/aggregates_only: o que pode ser republicado e o que só pode ser citado.- Verificação por sonda:
sources.tsé oSOURCE_REGISTRY_V2, com endpoints testados;regulation-sources.tsé o registro irmão para o rastreio de leis de IA. Osnso/*.jsonsão 27 listas de fontes por instituto nacional de estatística. - Anatomia de verificação: cada registro declara ainda seu
deep_link(a URL por-registro que é estampada emcitations.json), sua cadência (cadence_days), um specverifyde re-verificação por amostragem (refetch-compare: pedir de novo uma amostra e comparar com o que foi salvo) e umexpected_volumedimensionado para um sentinela de volume de ±50%. Atenção: o sentinela e o re-verificador são hoje contrato declarado do esquema, nenhum ingestor os executa ainda; o guardião que de fato roda a cada refresh é o guardião de frescor.
O esquema completo de um SourceRecord (scripts/sources/registry/schema.ts), cada campo com a regra que validateRegistry() aplica a ele:
| Campo | Tipo / valores | Regra em validateRegistry() |
|---|---|---|
key | UPPER_SNAKE estável | regex ^[A-Z0-9_]+$; duplicado ou inválido = erro |
tier · priority · status | primary/secondary/curated · P0/P1/P2 · wired/ready/blocked/research | o tick ingest:due do daemon drena linhas ready |
engine | um dos 10 AdapterEngine | engine desconhecido = erro |
license | kind (open/cc-by/non-commercial/share-alike/cite-only) + redistribute + aggregates_only? | o gate de licença (abaixo); aggregates_only + engine microdata = warn de lembrete: o adaptador agrega, nunca despeja linhas |
auth | none/env_key/registration/approval + env | env = variável de ambiente que o adaptador lê |
endpoint | padrão de URL com placeholders {iso3}/{code} | ausente = erro |
deep_link | padrão de URL por-registro | é o que se estampa em citations.json |
cadence_days | número | o ledger de frescor compara contra isto |
geos · geo_level | ISO3[] ou "ALL" · country/adm1/adm2/point/supranational | geo fora do conjunto de 26 (25 países + LATAM) = warn |
pillars | slugs de dimensão | vazio com engine ≠ provider = warn |
expected_volume | número ≥ 0 | negativo ou não numérico = erro; dimensiona o sentinela de ±50% |
verify | sample_n + method (refetch-compare/liveness-only/checksum) | bloco ausente ou sample_n < 0 = erro |
Os adaptadores são isolados por falha: um endpoint morto devolve [] em vez de quebrar a ingestão. A cadência (de quantos em quantos meses cada indicador é atualizado) vive junto à fonte e se materializa no ledger de frescor.
O gate de licença (em tempo de compilação)
A regra mais importante do registro não é de runtime: é de compilação. validateRegistry() rejeita qualquer fonte cuja licença diga redistribute: false mas esteja ligada a um engine que não seja provider. A condição exata é tripla: redistribute === false e engine ≠ provider e status === "wired": uma fonte cite-only pode ficar declarada como research ou blocked sem quebrar o build; o que ela não pode é estar ligada a um engine que produz valores. Republicar valores de uma fonte que só permite citar é um erro de compilação (assertRegistryValid() lança com a lista de chaves ofensoras), não um aviso que alguém poderia ignorar. A postura de licença de uma fonte decide se seus dados aparecem como indicador republicado, só como agregado, ou só como citação, e decide isso antes de o build produzir um único arquivo.
Esse mesmo gate se aplica aos dados aportados por terceiros via /contribuir: nada é redistribuído além do que sua licença permite. É o mecanismo que mantém honesto o Fundo Fiduciário de Dados.
As etapas de ingestão
scripts/ingest-all.ts orquestra três etapas, cada uma isolada por falha (uma etapa que falha não arrasta as outras):
runMultisource()→ células deparameter-cache/+ citações. É o grosso: o valor de cada indicador por país, com seucitation_id. Quando dois adaptadores emitem o mesmo id,mergeSeriesByYearune por ano: o overlay curado ganha em cada ano compartilhado e o histórico que o overlay não cobre é conservado.FORCE_REPLACE_IDSfica de fora dessa união: esses ids são substituídos por inteiro quando a metodologia muda ou o tip precisa recuar.runDocuments()→documents/enews/: documentos e notícias por dimensão e país.runSignals()→ sinais citados, extraídos por LLM, emsignals/.
Ao terminar, escreve refresh-meta.json. Há ingestores de domínio adicionais para orçamento aberto, liberdade econômica, liberdade digital, deriva autoritária, OGP, liberdade humana, liberdade de imprensa, regulação, observatório, o nível subnacional ADM1 e o grão cidade (ingest:city: determinista e sem rede: valores verificados duas vezes contra os endpoints oficiais citados e fixados como constantes com sua fórmula declarada, o mesmo padrão do ingestor de homicídios ADM1).
Existe ainda uma quarta via com cadência própria: o pulso social. ingest-social.ts (eventos GDELT + GKG + RSS social) e fetch-trends.ts alimentam as famílias social/, social-trends/, attention/ e civic/, com seus próprios bakes (bake-trends, bake-civic, bake-attention). Aparece em refresh-meta.json como a fonte social:gdelt, com contagem de posts.
E uma via determinística de sinais: observação da Terra. bake-earthobs-signals.ts (sem LLM e sem chaves) consulta duas fontes. Climate TRACE v7: emissões mensais de GEE por país para as 25 geografias, num único GET por mês cuja URL codifica o mês consultado; licença CC BY 4.0, com o inventário registrado no Zenodo (DOI conceitual 10.5281/zenodo.15014790). E o TerraBrasilis do INPE (CC-BY-SA 4.0): DETER (avisos mensais agregados de desmatamento e mineração na Amazônia, updated_date como data do último aviso; sinaliza-se o último mês completo porque o mês corrente é sempre parcial) e PRODES (taxa anual consolidada da Amazônia Legal). Emite sinais de tipo earth_obs em signals/medio-ambiente-clima__<ISO3>.json, junto aos sinais LLM da célula mas com outro contrato de procedência (ver Proveniência). Regras de honestidade: cada sinal cita o GET exato que produziu o valor; um país ausente ou em zero na resposta é omitido, nunca inventado; uma fonte caída deixa suas células intactas (o upsert substitui por fonte, não por célula); apenas estatísticas agregadas, sem imagens, sem geometrias, sem tasking de satélite nem revenda de imageria. Roda no tier docs depois da poda de sinais, que lhe aplica ainda um teto de idade por fonte para que um upstream caído não deixe sua última leitura na tela indefinidamente.
E uma quinta via: alta frequência (HF). ingest-hf.ts roda NASA POWER diariamente (um ponto capital por ISO3) e, na mesma execução, adaptadores de FIRMS, ClimateSERV CHIRPS, Ember mensal, Wikimedia, GHS, FAO ASIS, GFW e Meta Movement. Desde 30 de setembro de 2026 também estão registrados, e seguem sem publicação, sete feeds de comportamento: Banxico SIE (remessas mensais e SPEI diário, mais o CSV de FIX, taxa objetivo, TIIE 28 e reservas), preços de alimentos do PMA via HDX, demanda elétrica mensal da CAMMESA (espelho SSPM), ordens de compra mensais da ChileCompra, mix mensal de geração da Ember (participações renovável, fóssil e carvão; a geração total continua em EMBER_MONTHLY) e o arquivo diário da OpenAQ (média país de PM2.5 e PM10). A regra de publicação é estrita: apenas nasa-power.json é commitado e servido. Um armazém vazio (observations: []) ou um feed sem linhas publicáveis não é escrito sob public/data/hf-observations/: um 200 oco é um defeito, não um "em breve". check-hf-publish.ts bloqueia o build se aparecer qualquer JSON extra ou um POWER vazio. POWER não entra em parameter-cache nem em observations.csv (esse CSV já ultrapassa o teto de 100 MB do GitHub). O lane hf não move generated_at.
O bake
scripts/bake-all.ts transforma o cache bruto nos datasets derivados que as páginas consomem: narrativas → indicadores de fronteira → subnacional → briefs e contradições de pulso → previsões → shadows → grafo de personas → escores compostos → índice de mercados → _index.json. São 41 scripts bake-*.ts mais 10 geradores build-*: perto de 50 scripts de bake e geração: escores, mercados, V-Dem, exploração, insights, saúde do dado, sinais, coalizões, ontologia, tendências, cívica, atenção, feeds, contribuições, soberania de cômputo, convergência regional, nowcast de instabilidade, triangulação, narrativas e grafo de personas, além de geradores como build-democracy-index e build-search-index.
explore/, insights/ e ontology/ são re-baked em cada refresh programado de dados (tier corpus de data-refresh.yml, ao lado de split-citations.ts).
Dois geradores de domínio indexam famílias que você já viu na lista de datasets: build-cases-index.ts regenera o _index.json de cases/ (os precedentes e aprendizados por país, autorados arquivo a arquivo) e gen-elections-index.mjs o de elections/ (o calendário eleitoral regional).
Nenhum fato é "baked" dentro de um modelo: os fatos vivem nos dados com sua citação determinista; o bake só pré-calcula o que é derivável deles.
A API pública baked
O pipeline tem um quarto produto além dos dados da SPA: uma API estática somente-leitura em public/api/v1, re-baked a cada deploy por bake-api.ts: citations.csv/.json, freshness.json, contributions.json, futuros-data.xlsx e registros por país e por indicador com interoperabilidade M49/SDMX. Ela tem seu próprio gate: check-api.ts roda depois do bake e verifica que a API espelha os dados atuais (por exemplo, que a contagem de citações do seu índice coincide com citations.json). Por construção, a API nunca fica defasada do corpus. Referência completa em Public API.
As famílias de datasets (public/data/**)
O resultado são 69 famílias de dados estáticos. Entre as principais:
parameters.json(os 10 eixos),geographies.json(25 países + LATAM, com ISO3; os códigos M49 não vivem aqui, são unidos a partir de um mapeamento ISO3→M49 próprio debake-api.tsao fazer o bake da API pública).parameter-cache/(células indicador×país) eparameter-cache-adm1/(milhares de células subnacionais).Séries ADM1 de comportamento (2026-10-15, lote 03): Anatel (acessos BLF/SMP e densidade por UF, mensal/anual, BRA, dados abertos CC BY); BCB Pix (transações por pagador PF ao mês, mensal agregado a ano completo, BRA, ODbL); SII Chile (empresas e participação feminina por região, anual, CHL, aberto); Conab (rendimento/produção/área de grãos por UF, mensal na safra, BRA, cite-only com atribuição); CNJ Justiça em Números (congestão/IAD por tribunal estadual, anual, BRA, LAI; complementa CNJ DataJud); INEGI ENOE microdados (TIL1 de informalidade laboral por entidade, trimestral, MEX, Termos de Livre Uso; preferido sobre ENOE BIE). Cada célula cita o ZIP ou registro concreto; sem imputação.
Séries ADM1 e país de comportamento (2026-10-15, lote 04): ICFES Saber 11 (média departamental de punt_global, calendário A 2014-2022, COL, CC BY-SA 4.0 via datos.gov.co; família
parameter-cache-adm1-series-icfes/); IMSS segurados (postos, segurados, SBC e eventual por entidade, mensal, MEX, LIBRE USO MX; família irmãparameter-cache-adm1-series-icfes/); PNCP Pregão Eletrônico (contagens anuais por UF, BRA, dados abertos); MapBiomas LULC (vegetação nativa por ADM1, anual, BRA/ARG/CHL, CC BY 4.0); INPE PRODES (desmatamento anual Amazônia Legal e Cerrado por UF, km², BRA, CC BY-SA TerraBrasilis; células*__inpe_prodes.jsonemparameter-cache-adm1-series-icfes/para não colidir com MapBiomas nem orphan_series); OpenStreetMap amenities via Geofabrik taginfo (hospital/clínica/escola/banco por 100.000 hab., corte de fim de ano, 22 países, ODbL). Cada célula cita o registro concreto; sem imputação.SESNSP série estadual 2015-2025 + RNID 2026: snapshot
sesnsp-delitos-estatal.json;scripts/sources/adm1/bake-sesnsp-delitos.tsescreveparameter-cache-adm1-series/seguridad__MEX__*(homicídio doloso na manchete, cinco delitos emdetail[], blocomonthly_rnidà parte). Ruptura de série em 2026 (RNID): a metodologia nova nunca é emendada na série anual.Séries ADM1 de comportamento (2026-10-15, lote 05): SECOP II (participação da contratação direta por departamento, anual 2022-2025, COL, CC BY-SA 4.0 via datos.gov.co); SIAP fechamento agrícola (sinistralidade, valor, área e milho grão por entidade, anual, MEX, CC BY 4.0 SADER); TSE comparecimento eleitoral (1º turno presidencial por UF, bienal, BRA, CC BY; família
parameter-cache-adm1-series-icfes/para não colidir com PNCP); IBGE PNAD Contínua (desocupação, informalidade e rendimento real por UF, trimestral, BRA, SIDRA aberto; famíliaparameter-cache-adm1-series-icfes/). Cada célula cita o registro concreto; sem imputação.Séries nacionais de comportamento (2026-10-15, lote 06): CEPALSTAT uso do tempo e cuidado não remunerado (OIG; inatividade por cuidado, país, anual, CC BY via CEPALSTAT; citações ECLAC); UNESCO LLECE ERCE 2019 / TERCE 2013 via UIS (competência mínima em leitura/matemática no 6º ano, total e quintil pobre, 17 países, share-alike UIS); GBIF ocorrências (contagens anuais de registros e publicação doméstica, 25 países, agregados CC BY); Global Forest Watch / UMD Hansen perda de cobertura arbórea (ha, floresta primária, % da extensão 2000 e emissões brutas, anual, 25 países, CC BY 4.0; mantém-se o adaptador da API GFW frente ao espelho OWID da onda I); GitHub Innovation Graph ampliado (organizações, repositórios, colaboração LATAM/EUA, pushers Python e licença MIT, trimestral, 25 países, CC0). Cada célula cita o registro concreto; sem imputação.
Séries país de comportamento (2026-10-15, lote 07): Glottolog CLDF v5.3 (línguas vivas/em perigo/extintas e % em perigo, país, por edição, CC BY 4.0 Max Planck); UN Comtrade composição de exportações por capítulos SH (extrativas, agroalimentos, maquinaria, país, anual, cite-only agregados); Digital Policy Alert / SGEPT (eventos de política digital por país-ano, 16 países, CC BY-NC 4.0); EIA International Energy Statistics (uso per capita, intensidade PPP e perdas de rede, país, anual, domínio público EUA); Ember emissões do setor elétrico (intensidade gCO2/kWh, MtCO2 e % gás na geração, país, anual, CC BY 4.0; deep links corrigidos); EM-DAT perfis de país via HDX (eventos, climáticos, mortes e afetados, país, anual, não comercial CRED/UCLouvain); GEM Adult Population Survey (oito indicadores-chave de empreendedorismo, 10 países com dado fresco ≥2024, cite-only agregados). Cada célula cita o registro concreto; sem imputação.
Séries país de comportamento (2026-10-15, lote 08): HRMI Rights Tracker ESR (pontuações SERF educação/alimentação/saúde/moradia/trabalho, 23 países, edição 2022/dado 2019, CC BY-NC 4.0); UIT DataHub v3 (posse de celular, espectro IMT e banda larga móvel por 100 hab., país, anual, CC BY-NC-SA 3.0 IGO); Índice da Lista Vermelha UICN / ODS 15.5.1 via ONU (25 países, anual, não comercial); LAPOP AmericasBarometer (apoio à democracia, confiança, vitimização e coesão, 24 países, ondas 2025/26, agregados ponderados, não comercial); Latinobarómetro (apoio e satisfação com a democracia, 17 países, onda 2024, cite-only agregados); Media Cloud via Internet Archive Wayback (atenção mediática à IA por 10.000 matérias em ccTLD nacional, 20 países, anual, cite-only agregados). GFW TCL já ia no lote 06 (API WRI); o espelho OWID da onda I foi omitido. Cada célula cita o registro concreto; sem imputação.
Séries país de comportamento (2026-10-15, lote 09): ReliefWeb lista de desastres via HDX (contagens anuais de desastres e de desastres climáticos, 25 países, exportação diária / publicação anual, CC BY 4.0 OCHA); UCDP GED por tipo de violência (mortes não estatais, unilaterais e civis, 25 países, anual, CC BY 4.0; reutiliza a chave UCDP); WDPA áreas protegidas via WDI (terrestres e marinhas, 25 países, anual, CC BY 4.0 UNEP-WCMC/IUCN); OpenAlex facetas (participação de acesso aberto e trabalhos etiquetados ODS 3/4/7/10/13/16, 25 países, mensal, CC0; chave OPENALEX_FACETS distinta de OPENALEX); Overture Maps Places (densidade de lugares por 1.000 hab. e por categoria, 25 países, por release, CC0 1.0). IATI e IBTrACS já estavam em main (#1244, #1234) e foram omitidos. Cada célula cita o registro concreto; sem imputação.
Séries país de comportamento (2026-10-15, lote 10): OCDE PISA 2022 (médias de matemática, leitura e ciências, 14 países, trienal, CC BY-NC-SA 3.0 IGO); PSMSL nível médio do mar RLR (anomalia anual, 9 países, anual, cite Holgate et al. / PSMSL); FMI IFS via DBnomics (depreciação cambial e reservas sem ouro, 23 países, anual, agregados citados); OMPI IP Statistics (patentes e marcas por origem, 23 países, anual, CC BY 4.0). ONU Turismo já estava em main (#1237) e foi omitida. Cada célula cita o registro concreto; sem imputação.
parameter-cache-city/: o grão cidade, primeira coorte de cinco cidades âncora (CABA, CDMX, São Paulo município, Bogotá D.C., Santiago/RM) com dados apenas medidos dos seus institutos nacionais de estatística via rotas keyless machine-readable (SIDRA N6, GAIA/ITER, Series de Tiempo, SODA de datos.gov.co, SDMX do INE). É um armazém irmão do ADM1, não mais uma linha: três das cinco cidades coincidem com uma unidade ADM1 e o município de São Paulo colidiria com o slug do estado homônimo. O registro canônico vive emsrc/data/city-units.ts; o grão real de cada indicador é declarado por célula (p. ex. os indicadores de trabalho de Santiago só existem em grão região). O que a fonte não serve, como o Gini municipal do IBGE, a ENOE do INEGI (com token) ou os anexos do DANE atrás do seu WAF, é omitido e documentado, nunca imputado.hf-observations/: sónasa-power.jsoné publicado (NASA POWER não vazio). Os outros feeds HF, inclusive Banxico SIE, preços do PMA, CAMMESA, ChileCompra, mix Ember e arquivo OpenAQ, são ingeridos mas não commitados nem servidos; um arquivo oco é um defeito.citations.json: o registro central de citações (vários MB).documents/,news/,signals/,social/,social-trends/,attention/,shadows/.personas/(perfis +_index+_graph),state-history/,country-history/.scores.json(composto),data-health.json,frontier-indicators/,compute-sovereignty/,agi-economy/,dependency/,climate-action/.pulse/,regional-convergence/,subnational-convergence/,instability-nowcast/,triangulation/,uncertainty/,insights/.pilots/,pilot-archetypes/,financing-instruments/,coalitions/,positions/,cases/.regulation/,constitutional/,elections/,democracy/,transparency/,ai-governance/.markets/,metrics/,ontology/,civic/,gender-gap/,trends/.search-index.json(índice Voyage para o assistente),catalog.json,sdg-crosswalk.json,falsifications.json.
Frescor
A regra da plataforma: nenhuma observação publicada pode ter mais de dois anos. O limiar vive uma única vez, em STALE_AFTER_YEARS de src/lib/vintage.ts, e as três superfícies que o aplicam derivam dali: o selo de safra que o visitante vê (âmbar passada a regra), check-vintage no nível da cifra individual e check-freshness no nível da família de datasets (730 dias). Quando a fronteira do próprio publicador é mais velha que a regra, nada é maquiado e nenhum número é inventado: ou o dado é atualizado a partir de uma fonte corrente que cubra o mesmo conceito, ou essa fronteira é declarada com sua evidência e sua data de reverificação. Em 9 de setembro de 2026 há seis frentes assim, todas checadas ao vivo naquele dia: as cinco famílias derivadas do Subnational HDI v10.2 do Global Data Lab (13 de maio de 2026, cobertura até 2023, o release mais novo que o GDL publica) e a declaração anual de Cuba ao UN Comtrade, que não registra envio posterior a 2022. Os indicadores do Programa Estado de la Nación na Costa Rica são o mesmo caso uma escala abaixo, no nível da cifra: os oito mais velhos —investimento em saúde por pessoa (2015), rede viária total e gasto público em saúde e em educação (2019), cobertura florestal, emissões totais de CO₂ e evasão escolar primária e secundária (2020)— são exatamente a última observação que o PEN publica para a Costa Rica, verificada contra sua API em 9 de setembro de 2026. São servidos com o ano à vista e em âmbar, nunca como se fossem atuais.
public/data/refresh-meta.json é o ledger de frescor, com duas granularidades: o mapa indicators rastreia por-indicador o subconjunto Banco Mundial / WGI (49 códigos); todo o resto (884 séries no ledger de fontes assado) é rastreado em nível de feed no mapa sources (cerca de 200 entradas como social:gdelt ou doc:exa, com kind, last_refreshed, next_refresh_due e contagens como posts; o próprio mapa carrega a contagem vigente, que cresce com cada fonte nova). As linhas series:* carregam ainda cadência: cadence_months com cadence_basis: "observed" (mediana do espaçamento entre observações das séries que temos) ou cadence_basis: "stated" quando a cadência vem do calendário oficial de publicação do instituto. Hoje são sete as fontes auditadas contra seus calendários (IBGE, INEGI, DANE, INDEC e BCB mensal; Banxico e CEPALSTAT anual, porque delas só tomamos fechamentos anuais), que conservam o espaçamento observado em cadence_observed_months e vinculam o calendário em cadence_calendar_url. A forma de uma entrada por-indicador:
| Campo | Exemplo (SI.POV.GINI) | O que responde |
|---|---|---|
source / source_url | World Bank Open Data | de onde saiu? |
cadence_months / next_refresh_due | 12 / 2027-03-02 | quando toca atualizar? |
last_refreshed | 2026-07-28 | quando pedimos pela última vez? |
last_observation_year | 2025 | quão novo é o dado em si? |
countries_with_data / total_countries | 22 / 25 | quanta cobertura? |
source_frontier_year / source_frontier_checked_at | 2025 / 2026-07-23 | existe algo mais novo no upstream? |
freshness_status / freshness_note | current | veredicto: current, source_not_updated ou no_data |
A distinção que carrega o peso é last_refreshed vs last_observation_year: um pull de ontem com dado de 2023 não é uma falha do pipeline, e sim atraso do provedor, e source_frontier_year o demonstra, porque registra o ano mais novo que o upstream publica. É o que torna possível mostrar o vintage de uma cifra em vez de fingir que tudo está em dia. A superfície /confianza lê este ledger; /incertidumbre é outra coisa, expõe bandas de confiança do V-Dem a partir de uncertainty/vdem-ci.json, não este arquivo.
O ledger tem ainda um guardião ativo, não só uma tela. O runner multisource poda e reescreve células ao ingerir, então uma execução com um adaptador caído ou limitado poderia apagar em silêncio células que existiam, o defeito "meu fetch falhou, escrito em disco como não há nada". freshness-guard.py impede isso com três subcomandos sobre parameter-cache/:
snapshot <out.json> # antes da execução
para cada parameter-cache/<pilar>__<ISO3>.json, para cada indicador:
snap[id][celda] = { vintage: vintage_year, value, obj: <indicador completo> }
compare <before.json> # depois da execução
por indicador: gone (células que desapareceram)
regressed (vintage retrocedeu: after < before)
advanced (vintage avançou) · added (células novas)
reporta o total de células perdidas + regredidas
repair <before.json> --apply
restaura SOMENTE gone ∪ regressed, a partir do obj salvo no snapshot
advanced e added ficam intactos — um avanço genuíno nunca é revertido
sem --apply é dry run: lista o que restauraria, não toca o discoInvariante sutil do filtro --only=<substr>: o guardião filtra a linha de base com os mesmos termos que o snapshot vivo. Sem isso, todo indicador fora do filtro pareceria gone e o repair restauraria a plataforma inteira à linha de base, incluídas correções deliberadas posteriores. As execuções de refresh são não destrutivas por construção.
No prebuild, bake-source-ledger.ts faz o bake do ledger de fontes que alimenta /confianza e estampa em refresh-meta.json os campos de nível superior source_ledger_baked_at e source_ledger_series; nos refreshes de dados, recheck-wb-freshness.ts re-verifica os vintages do Banco Mundial contra o upstream e estampa wb_freshness_checked_at.
Os gates do prebuild
O prebuild é uma cadeia de gates encadeados com && no package.json; se qualquer um falha, o build falha e nada é implantado:
* = consultiva (--warn): reporta e sai 0.
Primeiro o terreno: dois typechecks (tsc -p tsconfig.scripts.json para os scripts de ingestão e bake, tsc -p tsconfig.server.json para o servidor do assistente e as funções), a suíte completa de testes (bun test --timeout 15000: 2.443 testes em 186 arquivos, incluindo o servidor do assistente, o handler MCP e os bakers) e build-positions-index --check. Depois, vinte e cinco verificações check-* com nome próprio, mais dois gates em modo --check sobre scripts que normalmente escrevem (build-positions-index, bake-trends-index). Duas são consultivas (--warn: reportam e saem 0, check-search-index, check-adm1-coverage); as demais fazem o build falhar, incluindo check-vintage, que deixou de ser consultiva em 9 de setembro de 2026, e a nova check-freshness.
Proveniência e coerência do corpus:
check-traced: toda cifra tem seu rastro até a fonte.check-signals: os sinais estão bem formados e citados. Os sinais LLM devem citar um documento do corpus da célula com a cifra verbatim do seu excerto; os sinaisearth_obs(determinísticos, sem documento irmão) passam uma comporta estrutural: host https em lista branca (apenasapi.climatetrace.orgeterrabrasilis.dpi.inpe.br), célula e fonte fixas, data ISO completa e cifra verbatim dentro do seu próprioclaim_es(com os mesmos dígitos emclaim_en/claim_pt).check-source-links: os links de citação apontam para o registro específico de país + indicador. A única exceção é a listaLANDING_OKdentro do próprio gate: um opt-out documentado por fonte (camadas curadas e internas que resolvem para /metodologia, camadas documentais EXA/GDELT/RSS/diários oficiais/sinais e umas poucas fontes sem URL estável por registro cujo destino honesto é sua própria página de dataset), cada um com sua justificativa no código. Todo o resto leva deep link ou o build falha.check-pilots: coerência dos pilotos.check-persona-scope: nenhum perfil pode ficar inalcançável. O<select>de país de /personas é construído a partir dos 25 canônicos, então um perfil arquivado sob umiso3fora desse conjunto era uma ficha completa e com fontes que nenhum visitante podia filtrar (a auditoria D-5 encontrou 50 de 1.384 assim: Barbados, Bahamas e um colunista radicado em Miami sobUSA). Não foram apagados, foram escalonados por tier; este gate torna o escalonamento vinculante.check-citations: integridade do registro de citações.check-parameter-cache-citations: cadacitation_iddeparameter-cache/resolve emcitations.json, sem recurso a uma citação sintética de reserva. A API pública já estava limpa; este gate mantém limpo o cache a partir do qual ela é assada.check-scores: coerência dos escores compostos (ver O Índice Futuros).check-provenance: rejeita hashes ou digests fabricados (stubs de sha256 truncados) em qualquer parte depublic/data; nasceu da auditoria de precisão de dados de julho de 2026. 9b.check-frontier-provenance: faz o build falhar se qualquer linha empublic/data/frontier-indicators/**carregarprovenance: "synthesised",simulated: true, umcitation_idque não resolve, ou um valor sob uma chave do catálogo de fronteira marcadaredistribute: false. É o gate que retirou o corpus fabricado de oito indicadores e mantém o corpus citado (97 indicadores × 25 países) honesto.colombia/check-real-data: separa o real do sintético no corpus da Colômbia, para que nenhuma cifra de demonstração seja servida sem seu banner.
Estilo, taxonomia e cobertura:
check-emdash-drift: a deriva de estilo (travessões) não reaparece no conteúdo já varrido.check-landing-stats: cada número impresso empublic/landing.htmlcontinua sendo o número que os dados dizem. A landing é um artefato editado à mão, a página de maior tráfego e a única sem componente, dicionário ou teste por trás; suas estatísticas eram livres para apodrecer e apodreceram (a auditoria de 13 de agosto de 2026 a encontrou anunciando 6.726 citações contra um corpus de 6.855, e "300+ pilotos" contra um índice de 337). O gate recomputa cada cifra a partir depublic/data/**do mesmo modo que a superfície correspondente, e imprime o literal a colar. Hoje verifica seis: fontes primárias distintas, países, eixos, citações, personas e instrumentos.check-docs-citations: cada cifra do corpus de citações escrita à mão emdocs/continua sendo a quecitations.jsondiz. É a gêmea decheck-landing-statspara o site de documentação: as contagens de citações e de fontes primárias vivem à mão no índice ES/EN/PT, em Procedência e citações, na edição em espanhol desta página e nos exemplos de/api/v1/metaemdev/public-api, sem componente, dicionário nem teste por trás, e apodreceram do mesmo modo: até agosto de 2026 os docs anunciavam ~6.850 citações (a cifra de julho) enquanto o corpus vivo já ia por 15.098, uma subestimação de 2,2x que nenhuma auditoria automática detectava porque nada conectava as duas. As cifras foram corrigidas em 4 de setembro de 2026; este gate é o que impede que voltem a se separar. Além dos slots declarados, varre todo odocs/em busca de afirmações com forma de contagem, então uma página nova com uma cifra rançosa também falha. As cifras históricas estão isentas se disserem de qual auditoria e de quando falam: narrar o passado é honesto, repeti-lo como presente não.check-basedosdados: a loja brasileira de grão municipal é vigiada com o mesmo contrato queparameter-cache: cadacitation_idresolve ao mesmo tempo nas citações próprias da loja e nocitations.jsonglobal; cada citação aponta para uma tabela específica do Base dos Dados (?table=<uuid>) e também para o registro da agência que produziu a cifra, porque o BD é um espelho e não o produtor; cada indicador declara seu próprio vintage, de modo que não se pode publicar um «último dado» misturado; e nenhuma coluna declarada pode vir vazia em todas as linhas. Esta última regra existe porque aconteceu: a receita estadual do SICONFI era selecionada por rótulo (Receitas Orçamentárias), rubrica que não existe nessa etapa contábil, e produziu 27 nulos que pareciam um buraco de dados e eram um bug do seletor. A loja cobre apenas o Brasil (grão município/UF), portanto o gate não exige cobertura de nenhum outro país; se a loja nunca foi ingerida, ela passa em verde: um checkout limpo continua compilando.check-catalog: o catálogo de datasets está completo e consistente.check-search-index(consultiva), o índice semântico cobre o corpus.check-law-term-index: o índice de termos legais cobre 100% do corpus regulatório (instrument_countderegulation/_index.json). Índice local: Voyage segue opt-in e falha fechado.bake-trends-index --check: o índice de tendências assado coincide com seus insumos.check-vintage: quantas cifras publicadas quebram a regra de safra de dois anos. O limiar e a ordem de resolução do ano vêm desrc/lib/vintage.ts, o mesmo módulo a partir do qual as tiras de manchete renderizam, então o gate mede o que o visitante vê. Existe porquebake-data-healthpontua uma célula pela idade mediana de seus indicadores: a plataforma reportava 2 células rançosas de 260 enquanto 27% das cifras individuais quebravam a regra. Foi consultiva até 9 de setembro de 2026 —media a regra sem poder aplicá-la— e hoje faz o build falhar acima de sua catraca de 8.978 cifras rançosas, que só pode descer. A única ressalva é a virada de ano:oldestAllowedrola com o calendário, então em 1º de janeiro uma coorte anual inteira fica rançosa de uma vez e a contagem salta milhares acima de um teto medido no ano anterior. Por isso a catraca registra o ano em que foi medida e, fora desse ano, o gate reporta em voz alta e sai 0 até que alguém volte a medir e confirme o novo teto. Um build quebrado que ninguém causou corrói o gate mais rápido que a deriva que ele vigia.check-freshness: nenhum dataset vivo da plataforma tem mais de dois anos. Ondecheck-vintageconta cifras isoladas dentro deparameter-cache/, este gate pergunta o que aquele estruturalmente não pode: se há um feed inteiro que ninguém conseguiu avançar. Percorre as quinze famílias de datasets quantitativos declaradas emscripts/lib/freshness.tse compara a observação mais recente de cada uma com o limite de 730 dias derivado do mesmoSTALE_AFTER_YEARS. As famílias com um arquivo por país são julgadas registro a registro, o único grão que detecta o defeito que o originou: o bake do UN Comtrade de 23 de julho de 2026 morreu após seis países e deixou 19 de 25 no ano comercial 2023, enquanto os seis já atualizados mantinham a cara da família em 2025. Nunca conta umgenerated_atnem umlast_refreshed—isso é quando nós rodamos, não quando o mundo foi medido— e descarta as projeções (o WEO do FMI vai até 2031, os cenários SSP do CCKP até 2080): uma previsão não é uma observação. Um ano é datado no fim desse ano, nunca em 1º de janeiro, porque arredondar na direção que lisonjeia é exatamente o erro que o gate procura. Quando a fronteira é do publicador e não nossa, ela é declarada como uma isenção com prazo de validade: quem publica, qual release, qual ano, a URL que prova, quando foi verificada ao vivo e até quando precisa ser verificada de novo. O gate falha se a isenção vence, se a fronteira declarada deixa de coincidir com o que os arquivos medem, ou se cobre dados que voltaram a estar frescos — é o que impede que a isenção honesta de hoje vire uma lista de exceções permanente.check-adm1-coverage(consultiva), o gate de honestidade da camada subnacional. "432 de 456 unidades ADM1 com dado real" era verdade apenas da sobreposição universal GDL; em nível de eixo nenhuma unidade levava mais de 5 dos 10 eixos medidos, cinco eixos estavam 100% modelados e 26 unidades tinham suas células escritas sob slugs que o app nunca pode pedir. Nada detectava isso, então derivou em silêncio por meses.check-city-cells: o gate de honestidade do grão cidade (parameter-cache-city/), estrito desde o nascimento (sem catraca: o armazém nasceu limpo). O contrato é apenas medido: os níveis de cobertura modelados são estruturalmente impossíveis neste armazém; cada indicador exige valor finito, ano vigente,citation_idterminado em-<ano>que resolve emcitations.jsone cuja linha carrega exatamente a mesmaurlque osource_urlda célula (a célula e sua citação não podem apontar para lugares distintos),source_urlcom deep link (nunca a landing da fonte) e um slug que resolve emsrc/data/city-units.ts. O registro é a afirmação de cobertura: cidade sem dado, cidade sem registrar.check-i18n: a cobertura ES/EN/PT não retrocede.check-taxonomy: a cópia de interface não volta aos substantivos aposentados para as dez medidas setoriais (diez parámetros,ten dimensions,dez dimensões) nem aponta a navegação para/governance. Os dez são ejes / axes / eixos.check-hf-publish: sobpublic/data/hf-observations/só pode vivernasa-power.json, e deve ser um armazém NASA POWER não vazio. Cascas vazias (observations: []) e feeds não publicados (CHIRPS, FIRMS, Ember…) são um defeito: servem um 200 que parece vivo.check-api: roda ao final, depois dos bakes de prebuild (bake-data-health,bake-source-ledger,bake-api,bake-feeds,bake-research-library), e verifica com sete grupos de asserções que a API pública estática espelha os dados atuais.bake-research-librarynão alimenta a API: escrevepublic/data/research-library.jsonepublic/research/<slug>.jsonpara a rota/biblioteca.
Os gates de proveniência em sentido estrito são o subconjunto check-traced, check-signals, check-source-links, check-citations, check-parameter-cache-citations, check-provenance e check-frontier-provenance: mas todos compartilham a mesma consequência: são a razão pela qual "toda cifra com sua fonte" não é um slogan, e sim uma invariante de compilação. Como uma citação se resolve em tela é explicado em Proveniência e citações.
Um padrão se repete nos gates mais novos (check-landing-stats, check-docs-citations, check-vintage, check-freshness, check-adm1-coverage, check-persona-scope): cada um nasceu de uma auditoria que encontrou uma afirmação verdadeira quando foi escrita e falsa quando foi lida, sem nada que a conectasse ao dado. O gate é essa conexão. É a mesma razão pela qual esta documentação existe e pela qual é auditada contra o código.