Skip to content

Otimização da procedência: roadmap técnico

A procedência do Futuros hoje é derivável: o deep link é reconstruído do citation_id, a bateria de gates do prebuild (rastreabilidade, deep links, citações, pontuações, procedência, catálogo, API — mais a suíte completa de testes) rejeita qualquer número sem rastro, e o recibo do fundo fiduciário é um hash reprodutível sobre um corpo canônico (Procedência e citações, O pipeline de dados). Esta página documenta a próxima fronteira: passar de "cada número tem sua fonte" para "cada número carrega uma prova de origem verificável por máquina, que um terceiro pode conferir sem confiar em nós".

Tudo o que segue é roadmap, não capacidade em produção, salvo onde marcado o contrário. A ordem é deliberada: cada fase reutiliza costuras que já existem no código (citation_id, stableStringify, receipt_hash, chain_anchor, refresh-meta.json, os gates check-*), de modo que nenhuma fase exige uma reescrita.

O modelo-alvo: quatro propriedades

Um número com procedência otimizada satisfaz quatro propriedades independentes, cada uma com seu mecanismo:

PropriedadePergunta que respondeMecanismo
IntegridadeEstes bytes são os que foram ingeridos?Endereçamento por conteúdo (SHA-256) das respostas upstream
AutenticidadeQuem produziu este artefato?Assinaturas Ed25519 sobre corpos canônicos + atestações de build
ReprodutibilidadePosso recomputá-lo e obter o mesmo?Bake hermético e determinista, insumos fixados por digest
TransparênciaA história pôde ser reescrita depois?Log append-only estilo Merkle com ancoragem externa periódica

A disciplina atual (citações deterministas + gates de build) dá integridade interna. As fases seguintes a tornam verificável de fora.

Fase A — Camada de aquisição endereçada por conteúdo

Hoje a ingestão escreve células derivadas; os bytes crus da resposta upstream são descartados. Isso torna impossível re-auditar uma transformação depois do fato: se o Banco Mundial revisa uma série, não podemos provar qual versão vimos.

O desenho: cada fetch de adaptador persiste sua resposta crua como um blob endereçado por conteúdo:

snapshots/
  sha256/ab/cd/abcd…ef        # bytes crus da resposta (gzip)
  manifests/wb-sp-dyn-le00-in-2026-07-30.json

O manifesto de fetch registra { url, method, request_headers_relevantes, etag, last_modified, fetched_at, digest, adapter, source_key }. Cada célula de parameter-cache/ ganha um campo derived_from: [digest…] — a lista dos blobs exatos dos quais foi derivada. O conjunto forma um DAG de Merkle: células → manifestos → blobs; o digest raiz de um bake resume todo o corpus de entrada em 32 bytes.

Consequências imediatas:

  • Re-auditoria retroativa. Qualquer defeito de transformação pode ser reproduzido contra os bytes originais, não contra o que o upstream sirva hoje.
  • Detecção de revisões upstream. Um etag/digest distinto na mesma URL distingue "a fonte revisou sua série" de "nosso pipeline mudou" — dois eventos que hoje são indistinguíveis.
  • Deduplicação de graça. O endereçamento por conteúdo colapsa respostas idênticas entre execuções; o custo de armazenamento cresce com a mudança real, não com a cadência de refresh.

A costura existente: scripts/freshness-guard.py já implementa snapshot→compare→repair para auditorias pontuais; a fase A o generaliza de ferramenta de auditoria para invariante do pipeline.

Fase B — Grafo de linhagem PROV-O consultável

/linaje narra a origem de cada série; a fase B o torna um grafo formal usando o vocabulário W3C PROV-O:

  • Cada blob da fase A é uma prov:Entity; cada execução de adaptador ou script bake-* é uma prov:Activity (prov:used → insumos, prov:generated → saídas); o pipeline e os operadores são prov:Agent.
  • Cada célula gerada no bake exporta sua cadeia como JSON-LD sob a API pública: GET /api/v1/prov/{indicator}/{iso3} devolve o subgrafo mínimo que conecta o número em tela aos digests de seus blobs de origem.
  • O grafo é derivado, não mantido à mão: é emitido como subproduto da instrumentação dos ~50 scripts de bake, com um wrapper comum que registra (insumos lidos, saídas escritas, digest de cada uma, versão do script).

O critério de sucesso é falseável: para qualquer número visível na plataforma, um cliente sem acesso ao repo pode percorrer o JSON-LD desde o citation_id até um digest de bytes crus, e verificar cada aresta com hashes.

Fase C — Bake reprodutível + atestações de build

A reprodutibilidade converte a linhagem em algo conferível, não só declarado:

  1. Bakes herméticos. Cada bake-*.ts declara seus insumos por digest (fase A) e fica proibido de tocar a rede; as fontes de não-determinismo (timestamps, ordem de iteração de objetos, floats) são canonicalizadas — stableStringify já existe para os recibos do fundo fiduciário (server/trust/ledger.ts: serialização recursiva com chaves ordenadas, sobre a qual receipt_hash = sha256(corpo canônico); o recibo é determinista dado o quádruplo contribuição + issued_at + nonce + salt, e por isso reprodutível de forma independente) e é promovido a serializador de todo artefato gerado no bake. Meta: scores.json bit a bit idêntico dado o mesmo conjunto de insumos.
  2. Atestações estilo in-toto/SLSA. Cada artefato de public/data/** e public/api/v1/** é acompanhado de uma atestação assinada: { subject: digest_do_artefato, materials: [digests_de_insumos], builder: {repo, commit, script, versão}, invocation: {argv, env_permitido} }, assinada com Ed25519 por uma chave de build publicada. São publicadas sob public/api/v1/attestations/.
  3. Verificação por terceiros. Com (1) + (2), um auditor externo — uma universidade, um banco multilateral, um governo que roda o mirror soberano — recomputa o bake sobre os mesmos blobs e compara digests. A confiança deixa de ser "acreditamos no Futuros" e passa a ser "nós recomputamos".

Nota de honestidade: a autenticação de emissor por HMAC do recibo do fundo fiduciário já está construída e é ativada por ambiente (TRUST_RECEIPT_HMAC_KEY): com a chave configurada, o recibo passa a esquema v2 e carrega uma assinatura HMAC-SHA256 sobre seu receipt_hash. Isso autentica o emissor mas não é verificável por terceiros, porque a verificação exige a chave secreta; a verificabilidade pública com Ed25519 segue no roadmap, e a chave de assinatura de build desta fase é seu pré-requisito.

Fase D — Log de transparência com ancoragem externa

Um ledger append-only operado pelo mesmo ator que escreve nele prova pouco: poderíamos reescrever a história e serví-la de novo. A fase D o torna economicamente impossível de falsificar:

  • Árvore de Merkle estilo RFC 6962 (Certificate Transparency) sobre três séries: o registro de citações, o ledger do fundo fiduciário e as atestações de build. Cada entrada nova produz um checkpoint assinado {tree_size, root_hash, timestamp}.
  • Provas de inclusão e consistência. Um recibo de contribuição ganha uma prova de inclusão de ~log₂(n) hashes; quaisquer dois checkpoints admitem prova de consistência (nada foi apagado nem reescrito entre eles). O receipt_hash existente é exatamente a folha de que a árvore precisa — zero migração de esquema. (E o recibo já sela salt_version — uma etiqueta pública one-way do salt que produziu o contributor_id — de modo que uma rotação futura de TRUST_ID_SALT não invalida a verificabilidade nem a revogabilidade de recibos antigos.)
  • Ancoragem externa periódica. O root é ancorado fora da nossa infraestrutura com cadência fixa: timestamping RFC 3161 e/ou OpenTimestamps (agregação no Bitcoin, custo ~zero), com o slot chain_anchor do recibo — reservado desde o dia um — recebendo o identificador de ancoragem. Falsificar a história passada exigiria falsificar também a ancoragem externa datada.
  • Monitores. O checkpoint assinado é publicado na API pública; qualquer terceiro pode rodar um monitor que verifique consistência entre checkpoints — o mesmo modelo de auditoria distribuída do CT.

A forma do log, em esquema:

Fase E — Credenciais de conteúdo nos artefatos exportados

A procedência hoje viaja com o embed via citação sintética (Procedência); ela se perde no momento em que alguém exporta um PNG/SVG/CSV e o cola num relatório. A fase E anexa C2PA Content Credentials a cada export:

  • O manifesto C2PA embutido declara: emissor (Futuros), os citation_id de cada série plotada, digest do dataset de origem, timestamp assinado, e a asserção de que o render foi produzido a partir de dados citados sem edição manual.
  • Os CSV/XLSX de /datos-abiertos ganham um sidecar de atestação (.csv + .csv.att.json) com o mesmo conteúdo — o formato tabular não admite manifesto embutido.
  • Resultado: um gráfico do Futuros que circula pelo WhatsApp ou por um deck ministerial continua verificável — qualquer verificador C2PA recupera as citações e o digest, e detecta edições.

Fase F — SLOs de frescor, deriva e ausência tipada

As fases A–E provam de onde veio um número; a fase F governa sua qualidade temporal — e codifica a lição mais cara das auditorias de dados deste projeto.

SLOs de frescor. refresh-meta.json já registra cadência e vencimento por fonte — hoje com last_refreshed / next_refresh_due em nível de feed (social:gdelt, doc:perplexity, …) e acompanhamento por indicador só para o subconjunto WB/WGI (49 códigos); o resto do corpus (884 séries no ledger de fontes) é rastreado em nível de feed, com o rollup de vintage em data-health.json. A fase F os converte em objetivos de nível de serviço com orçamento de staleness: cada fonte declara {cadência, carência, severidade}; o gate passa de binário (vencida/não) a um orçamento agregado que pode fazer o build falhar quando o corpus como um todo envelhece além do limiar, mesmo que nenhuma fonte individual esteja crítica.

Detecção estatística de deriva. Sobre os blobs da fase A: quando um refresh traz uma série revisada, um teste de deriva distribucional (PSI / Kolmogorov–Smirnov sobre a série sobreposta) classifica a mudança como revisão menor (re-bake silencioso com nota), revisão estrutural (exige entrada no changelog da fonte e re-verificação das células derivadas) ou anomalia de transporte (bloqueia o refresh — provavelmente é um erro nosso ou do upstream, não um dado novo). Complementa a detecção de anomalias ano a ano já publicada na camada de saúde do dado (|z| > 4 + piso de 10 pp, ver Metodologia).

Ausência tipada. O defeito recorrente mais perigoso encontrado nas auditorias internas do pipeline: um fetch que falhou escrito em disco como "não há dado". Uma célula vazia deve declarar por que está vazia, com um enum fechado:

absence: "no_data"        # a fonte afirma que não existe medição
       | "not_collected"  # fora do escopo declarado da fonte
       | "fetch_failed"   # nosso transporte falhou — NÃO se sabe nada do valor
       | "license_gated"  # existe, mas a licença só permite citação
       | "revoked"        # existiu, o contribuinte revogou o consentimento

Os gates de build tratam fetch_failed como erro de refresh, jamais como dado: um valor prévio nunca é sobrescrito com uma ausência de transporte. A distinção license_gated/revoked conecta com a porta de licença e torna a revogação visível no corpus em vez de silenciosa.

Fase G — Prova ZK de registro

As fases C e D deixam o fundo fiduciário com duas peças: um compromisso determinista por registro e um log público que inclui esse compromisso. A fase G adiciona a terceira: provas de conhecimento zero que demonstram um predicado sobre o conteúdo de um registro sem revelar o registro.

A cadeia de dependência, elo por elo:

  1. Corpo canônico + receipt_hash (em produção hoje; verificável por hash, sem assinatura). stableStringify produz uma serialização determinista do recibo e receipt_hash = sha256(corpo canônico). É o único elo que já existe: um compromisso de 32 bytes por contribuição.
  2. Prova de inclusão de Merkle (fase D, roadmap). Situa esse compromisso num log append-only com ancoragem externa. Sem D, uma prova ZK sobre um recibo não diz nada sobre o corpus: fala apenas de um blob que ninguém mais viu.
  3. Prova ZK de registro (esta fase). Um circuito toma o corpo canônico como testemunha privada, o receipt_hash mais a raiz do log como entradas públicas, e prova afirmações do tipo "existe um registro incluído no checkpoint N cujo privacy é aggregates_only e que não foi revogado", sem expor contribuinte, dataset nem nenhum outro campo.

O desenho existente torna o circuito tratável: a folha da árvore é exatamente o receipt_hash, e o corpo canônico já é uma serialização estável com chaves ordenadas, ou seja, uma testemunha bem definida. A fase G não pede um redesenho do recibo; pede que D opere primeiro.

O que desbloqueia: divulgação seletiva (um auditor verifica uma propriedade de um registro sensível sem vê-lo), agregados demonstráveis (as contagens públicas por modo de privacidade passam de afirmação a prova) e o pré-requisito direto do roadmap ZK do pilar 2 (ver abaixo).

Estado honesto: não existe circuito, nem protótipo, nem escolha de esquema de prova. É a última fase da cadeia criptográfica e não começa antes de D estar em produção.

Fase H — Níveis de sensibilidade e criptografia por registro

O ponto de partida, verificável em server/trust/ledger.ts:

  • PrivacyMode é metadado declarado, não um controle técnico. O contribuinte escolhe open | aggregates_only | clean_room | private_compute; o modo governa a pontuação e como a contribuição é agregada, mas hoje não ativa criptografia nem controle de acesso criptográfico algum.
  • O armazenamento é em claro. O ledger persiste os registros sem criptografia no backend do operador.
  • A pseudonímia vem de TRUST_ID_SALT. O contributor_id é um hash com salt do email, com salt_version selado no recibo para que a rotação de salt não quebre a revogação. É pseudonímia, não criptografia: protege a identidade diante de leitores do ledger, não o conteúdo diante do operador.

A fase H fecha a distância entre o declarado e o aplicado com dois movimentos:

  1. Níveis de sensibilidade por registro. Cada registro é classificado num nível fechado: T0 público, T1 pseudonimizado (o estado atual), T2 sensível, criptografado em repouso, T3 nunca sai do contribuinte (o "computar sem possuir" que private_compute já declara). O nível padrão deriva do PrivacyMode declarado, que deixa de ser só uma etiqueta.
  2. Criptografia por registro com chaves por contribuinte. Os níveis T2 e T3 usam envelope encryption: uma chave de dados por registro, envolvida por uma chave por contribuinte. A revogação ganha um mecanismo criptográfico: destruir a chave (crypto-shredding) torna o registro ilegível sem reescrever o log, compatível com a árvore append-only da fase D, onde o receipt_hash permanece como evidência de que o registro existiu.

Dependências: a criptografia em repouso não exige nem G nem D, mas a evidência verificável de uma revogação (provar que a capacidade de descriptografar foi destruída) se apoia sim no log da fase D. E H é o pré-requisito de dados da inferência ZK do pilar 2: sem registros criptografados não há "inferência sobre registros criptografados".

Um único fio com o pilar 2: inferência ZK sobre registros criptografados

O roadmap do pilar 2, Modelo Soberano inclui inferência com conhecimento zero sobre registros criptografados do fundo fiduciário. Esse item e as fases G e H desta página são uma única cadeia de dependência, não promessas paralelas:

receipt_hash sobre corpo canônico (em produção) → prova de inclusão de Merkle (fase D) → prova ZK de registro (fase G) + registros criptografados por nível (fase H) → inferência ZK sobre registros criptografados (pilar 2).

Nenhum elo depois do primeiro existe hoje. Se alguma página desta documentação chegasse a apresentar a inferência ZK do pilar 2 como capacidade sem que G e H operem aqui, isso seria um defeito reportável no mesmo espírito do log de falsificações.

Sequência e dependências

FaseDepende deCusto dominanteO que desbloqueia
A — CAS de aquisiçãoArmazenamento de blobs (cresce com a mudança, não com a cadência)Re-auditoria, detecção de revisões, o DAG
B — Linhagem PROV-OAInstrumentar os ~50 scripts de bake com um wrapper comumProcedência consultável por máquina, por célula
C — Bakes reprodutíveis + atestaçõesACanonicalizar o não-determinismo; gestão da chave de buildVerificação por terceiros; a assinatura do recibo
D — Log de transparência + ancoragemC (chave)Operar o log + monitoresHistória não-reescrevível; chain_anchor deixa de ser null
E — Credenciais C2PACTooling de manifestos no pipeline de exportProcedência que sobrevive fora da plataforma
F — SLOs + deriva + ausência tipadaA (para deriva)Migração do esquema de células para o enum de ausênciaFrescor governado; fim da classe de defeito "fetch falhou = não há dado"
G — Prova ZK de registroDDesenho do circuito e escolha do esquema de provaDivulgação seletiva; agregados demonstráveis; o pré-requisito ZK do pilar 2
H — Sensibilidade + criptografia por registroD (para evidência de revogação)Gestão de chaves por contribuinte; migração do armazenamentoCriptografia em repouso por nível; revogação por destruição de chave

O que cada fase torna verificável — e quem pode conferi-lo sem confiar no Futuros:

FaseO que se torna verificávelVerificadorArtefato que o prova
AQue os bytes upstream são exatamente os ingeridosAuditor com acesso aos blobsDigest SHA-256 + manifesto de fetch
BA cadeia completa célula → blob de origemQualquer cliente HTTP, sem acesso ao repoJSON-LD sob /api/v1/prov/…
CQue o bake é recomputado bit a bitTerceiro que roda o mirror soberanoAtestação assinada Ed25519
DQue a história não foi reescritaMonitor externo contínuo, estilo CTProvas de inclusão/consistência + ancoragem datada
EA procedência de um export fora da plataformaQualquer verificador C2PA padrãoManifesto embutido ou sidecar .att.json
FPor que uma célula está vazia e quanto o corpus envelheceuOs gates de build + o leitorEnum de ausência + orçamento de staleness
GUm predicado sobre um registro, sem revelar o registroQualquer verificador com o checkpoint do logProva ZK + prova de inclusão
HQue uma revogação destruiu a capacidade de descriptografarAuditor com o log e o registro de chavesEvento de destruição de chave ancorado no log

A e F-ausência-tipada são os pontos de partida corretos: A é o pré-requisito de tudo o que é criptográfico, e a ausência tipada elimina hoje a classe de defeito que mais vezes produziu dados falsos-por-omissão. D e E são os de maior visibilidade externa, mas só fazem sentido sobre C. G e H fecham a cadeia: G só existe sobre D, e a inferência ZK do pilar 2 só sobre G e H.


A regra que governa todo o roadmap é a mesma do resto da plataforma: nenhuma fase é anunciada como capacidade até que sua verificação seja executável por um terceiro. Enquanto isso, esta página é o compromisso público de para onde se otimiza — no mesmo espírito falseável do log de falsificações.

Cada número com sua fonte — a rastreabilidade é o contrato.