Skip to content

Catálogo CVM (YAML-fonte)

Conteúdo bruto do arquivo-fonte para referência — a documentação curada está nas páginas de conjuntos de dados e tabelas.

# ────────────────────────────────────────────────────────────
# CVM dataset registry — layout contract v2
# Adding a new dataset should be a YAML entry, not new code.
#
# layout ∈ csv_unico | zip_uma_tabela | zip_multi_tabela
#   csv_unico        — one CSV, one table
#   zip_uma_tabela   — zip of N CSVs, same schema, unioned into one table
#                      (equality of column sets is asserted before union)
#   zip_multi_tabela — zip of N CSVs, N distinct schemas → N tables, each
#                      with its own chave. Bronze gains a tabela= partition.
#
# Every file extracted from a zip must match exactly one declared `tabelas`
# entry for the competencia being built — zero or multiple matches is a
# hard error (ciano_lake/bronze/writer.py), never a silent union.
# ────────────────────────────────────────────────────────────

- id: cad_cia_aberta
  fonte: cvm
  dominio: cia_aberta
  periodicidade: diaria
  encoding: cp1252
  sep: ";"
  snapshot: true
  partes:
    - nome: unica
      url: https://dados.cvm.gov.br/dados/CIA_ABERTA/CAD/DADOS/cad_cia_aberta.csv
      layout: csv_unico
      tabelas:
        - nome: cad_cia_aberta
          chave: [cnpj_cia, cd_cvm, tp_merc]
          chaves_permitem_nulos: [tp_merc]
          # Milestone 1 — verificado contra dados reais (ver ARCHITECTURE.md Sec 9)

- id: cad_fi
  fonte: cvm
  dominio: fundos
  periodicidade: diaria
  encoding: cp1252
  sep: ";"
  snapshot: true
  partes:
    - nome: unica
      url: https://dados.cvm.gov.br/dados/FI/CAD/DADOS/cad_fi.csv
      layout: csv_unico
      tabelas:
        - nome: cad_fi
          # GRAIN (decisao do usuario, opcao (a)): uma linha por fundo por
          # atribuicao de gestor — GESTOR/CPF_CNPJ_GESTOR sao parte da chave.
          # Este cadastro NAO e um registro por fundo: o mesmo cnpj_fundo+
          # tp_fundo+classe aparece varias vezes quando o gestor troca, e
          # CPF_CNPJ_GESTOR e NULL/empty em ~58% das linhas (27,041/46,806)
          # — por isso fica em chaves_permitem_nulos.
          chave: [cnpj_fundo, tp_fundo, classe, cpf_cnpj_gestor]
          chaves_permitem_nulos: [classe, cpf_cnpj_gestor]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 180
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido com probe_dataset direto contra o
          # CSV raw real: baixado=2026-08-14 e 2026-08-20, numeros identicos):
          # 46,806 linhas, excess=138, dup_groups=124, TODOS nao-exatos
          # (exact=0; 117 grupos de 2 linhas + 7 de 4). Categoria CONHECIDA,
          # nao misterio individual — os grupos sao eventos de historico do
          # cadastro do MESMO fundo+gestor (o gestor e identico dentro de cada
          # grupo, pois esta na chave; nenhum grupo e troca de gestor):
          #   1) 45 grupos variam os campos de registro (CD_CVM/DT_REG/
          #      DT_CANCEL/DT_CONST/DT_INI_SIT) — o fundo foi re-registrado
          #      com novo codigo e datas (ex.: CD_CVM 109009 -> 121369 com
          #      DT_REG 2009 -> 2021, mesmo CNPJ e gestor);
          #   2) 79 grupos tem campos de registro identicos e variam so em
          #      prestadores/datas de exercicio (CNPJ_AUDITOR, CNPJ_CUSTODIANTE,
          #      CNPJ_ADMIN, DT_INI_EXERC/DT_FIM_EXERC, DT_PATRIM_LIQ —
          #      CVM publica mais de uma linha para a mesma inscricao);
          #   3) 0 grupos com VL_PATRIM_LIQ divergindo na mesma DT_PATRIM_LIQ
          #      (nenhuma contradicao de valor; variacoes de patrimonio sempre
          #      acompanham DT_PATRIM_LIQ diferente).
          # CORRECAO ao comentario anterior ("grupos de fundo SEM gestor"):
          # apenas 41/124 grupos tem CPF_CNPJ_GESTOR em branco; 83 tem gestor.
          # So 1/124 grupos varia em SIT (confirma a leitura historica, nao erro).
          # Chave nao fecha com acrescimos honestos (re-medido): +cd_cvm=93,
          # +dt_reg,+dt_cancel=93, +cnpj_auditor=74, combinacao plena de
          # colunas de identidade=33; so adicionar colunas de VALOR
          # (VL_PATRIM_LIQ, DT_PATRIM_LIQ) chega a 0 — exatamente o que o gate
          # existe para impedir (numero na chave derrota o proposito). Cap
          # excesso exato 20 (medido 0 hoje, folga para republicacao pontual);
          # cap grupos residuais 180 (~1,45x os 124 medidos — categoria
          # conhecida e estavel em 2 baixadas/6 dias). Cada grupo residual e
          # escrito em _residuos.json ao lado da particao promovida; a visao
          # silver "current fund" (uma linha por cnpj_fundo, regra de
          # desempate documentada) resolve o fan-out a jusante — ver
          # ciano_lake/silver/fundos/cad_fi.py e ARCHITECTURE.md Sec 6.12.

- id: inf_diario_fi
  fonte: cvm
  dominio: fundos
  periodicidade: mensal
  grao_competencia: mes
  encoding: cp1252
  sep: ";"
  snapshot: false
  restatement: false
  partes:
    - nome: unica
      url: https://dados.cvm.gov.br/dados/FI/DOC/INF_DIARIO/DADOS/inf_diario_fi_{aaaamm}.zip
      layout: zip_uma_tabela
      tabelas:
        - nome: inf_diario_fi
          arquivo: "inf_diario_fi_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, id_subclasse]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [id_subclasse]
          # TOLERADA (sweep 202508-202608, 13 zips locais): maximo=2 excess,
          # 2/2 grupos byte-identicos em 202607; todas as outras competencias
          # fecharam em 0. Cap 5. O arquivo e diario dentro da particao mensal
          # (202607: 585.157 linhas), nao uma linha mensal por fundo.
          # id_subclasse permanece whitelisted (~96% NULL/empty: fundos sem
          # subclasse); as demais colunas da chave passaram o gate de null-rate.

# ────────────────────────────────────────────────────────────
# fidc_inf_mensal — shape D (layout temporal hibrido)
#
# VERIFICADO empiricamente nas sessoes:
#   - partes/DADOS/ tem zips mensais a partir de 202501 (inf_mensal_fidc_202501.zip)
#   - partes/DADOS/HIST/ tem zips anuais ate 2024 (inf_mensal_fidc_2024.zip),
#     cada um contendo os 12 meses daquele ano
#   - a tabela tab_viii NAO existe na era historico: abri os zips anuais
#     2013..2024 e nenhum contem inf_mensal_fidc_tab_VIII_*.csv — probe falha
#     com "matched no file" para toda competencia HIST. tab_VIII so existe na
#     era corrente (2025+). O membre-set HIST ainda varia por ano, ver nota
#     da parte historico abaixo. A afirmacao "17 arquivos I a X_7" do desenho
#     original vale SO para 2023/2024 (17, sem VIII) e corrente (18, com
#     VIII); 2019-2022 tem 16 (sem VIII e sem X); 2013-2018 tem arquivos POR
#     ANO (sem token de mes) e nao cabem no grao mensal declarado.
#   - CNPJ_FUNDO_CLASSE / TP_FUNDO_CLASSE (nao CNPJ_FUNDO / TP_FUNDO) sao as
#     colunas reais de identificacao do fundo/classe
# ────────────────────────────────────────────────────────────
- id: fidc_inf_mensal
  fonte: cvm
  dominio: fundos
  periodicidade: mensal
  grao_competencia: mes
  encoding: cp1252
  sep: ";"
  snapshot: false
  restatement: true
  partes:
    - nome: corrente
      url: https://dados.cvm.gov.br/dados/FIDC/DOC/INF_MENSAL/DADOS/inf_mensal_fidc_{aaaamm}.zip
      vigencia: { de: "202501", ate: null }
      layout: zip_multi_tabela
      tabelas:
        - nome: tab_i
          arquivo: "inf_mensal_fidc_tab_I_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (sweep 202501-202607, 19 meses locais): somente 202509
          # duplicou — 1 excess, 1/1 grupo byte-identico. Cap 5.
        - nome: tab_ii
          arquivo: "inf_mensal_fidc_tab_II_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico — E6 do artefato bucket-c).
          # Demais meses 0. Cap 5.
        - nome: tab_iii
          arquivo: "inf_mensal_fidc_tab_III_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
        - nome: tab_iv
          arquivo: "inf_mensal_fidc_tab_IV_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zip atual 202509 no
          # servidor): 1 grupo residual variando TAB_IV_B_VL_PL_MEDIO.
          # Demais meses 0. Caps 5/5.
        - nome: tab_v
          arquivo: "inf_mensal_fidc_tab_V_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
        - nome: tab_vi
          arquivo: "inf_mensal_fidc_tab_VI_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
        - nome: tab_vii
          arquivo: "inf_mensal_fidc_tab_VII_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
        - nome: tab_viii
          arquivo: "inf_mensal_fidc_tab_VIII_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, sequencial]
          # VERIFICADA: tabela omitida do catalogo original (pulava tab_vii ->
          # tab_ix). Probe com [BASE, sequencial]: excess_rows = 0 em
          # 202603 (40,068), 202604 (40,707) e 202605 (40,635) - medido, nao
          # suposto. sequencial nao e nulo.
        - nome: tab_ix
          arquivo: "inf_mensal_fidc_tab_IX_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
        - nome: tab_x
          arquivo: "inf_mensal_fidc_tab_X_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
        - nome: tab_x_1
          arquivo: "inf_mensal_fidc_tab_X_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_classe_serie, id_subclasse]
          chaves_permitem_nulos: [id_subclasse]
          # id_subclasse ~49% NULL (5,420/11,067 em 202603, a mesma razao nas
          # outras competencias) - whitelisted no gate de null-rate. Probe:
          # excess_rows = 0.
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 3 excess (3 grupos byte-identicos). Demais meses 0. Cap 5.
        - nome: tab_x_1_1
          arquivo: "inf_mensal_fidc_tab_X_1_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
        - nome: tab_x_2
          arquivo: "inf_mensal_fidc_tab_X_2_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 3 excess (3 grupos byte-identicos). Demais meses 0. Cap 5.
        - nome: tab_x_3
          arquivo: "inf_mensal_fidc_tab_X_3_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep 202501-202607, 19 meses locais): maximo
          # exato=4 excess (202505); maximo residual=6 grupos (202505), variando
          # somente TAB_X_VL_RENTAB_MES. 202501 mediu 14 excess (2 exatos +
          # 5 residuais). Caps 5/10; contradicao de rentabilidade da fonte.
        - nome: tab_x_4
          arquivo: "inf_mensal_fidc_tab_X_4_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_tp_oper, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep 202501-202607, downloads atuais de
          # 2026-09): maximo exato=11 excess em 202509 (12 totais, 12 grupos,
          # 11 exatos + 1 residual); maximo residual=6 grupos em 202504 e
          # 202505 (0-1 exato). 202506-202508 e 202510-202607 fecharam em 0.
          # Residuais variam somente TAB_X_VL_TOTAL/TAB_X_QT_COTA —
          # contradicao de valor da fonte. Era VERIFICADA por extrapolacao
          # (0 em 202603/202604/202605); o restatement de 202509+ quebrou.
          # Caps 15/10.
        - nome: tab_x_5
          arquivo: "inf_mensal_fidc_tab_X_5_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
        - nome: tab_x_6
          arquivo: "inf_mensal_fidc_tab_X_6_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep 202501-202507 + 202509, downloads
          # atuais de 2026-09): maximo exato=3 excess em 202509 (3 grupos
          # byte-identicos); 202501/502 mediram 3 totais (1 exato + 1 residual
          # variando TAB_X_PR_DESEMP_*); 202505 = 1 exato; demais 0. Residual
          # existe, logo tolerada pura e invalida. Era VERIFICADA por
          # extrapolacao. Caps 5/5.
        - nome: tab_x_7
          arquivo: "inf_mensal_fidc_tab_X_7_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 202509 no servidor):
          # 1 excess (1 grupo byte-identico). Demais meses 0. Cap 5.
    - nome: historico_2013_2018
      url: https://dados.cvm.gov.br/dados/FIDC/DOC/INF_MENSAL/DADOS/HIST/inf_mensal_fidc_{aaaa}.zip
      vigencia: { de: null, ate: "201812" }
      layout: zip_multi_tabela
      filtro_linha: DT_COMPTC
      raw_grao: ano
      # MEDIDA (zips anuais 2013..2018, os 6 anos da era, 72 competencias com o
      # split por DT_COMPTC do probe): 14 arquivos POR ANO em TODOS os anos —
      # membro-set estavel I..VII + IX + X_1..X_6 (sem VIII, sem X, sem X_7,
      # sem X_1_1). Schema PRE-classe em toda a era: CNPJ_FUNDO / DENOM_SOCIAL /
      # DT_COMPTC (sem TP_FUNDO, sem TP_FUNDO_CLASSE, sem ID_SUBCLASSE); tab_x_1
      # usa TAB_X_NR_COTST. Chave base [cnpj_fundo, dt_comptc]; tab_x_1/2/3/6
      # ganham tab_x_classe_serie e tab_x_4 ganha tab_x_tp_oper +
      # tab_x_classe_serie (mesma forma da era corrente).
      # NENHUMA tabela fecha em excess=0: ~13 fundos aparecem DUAS VEZES no
      # mesmo mes (CVM republicou a linha byte-identica e/ou reafirmou valores —
      # mesmo CNPJ_FUNDO, colunas de VALOR divergentes, nenhuma coluna de
      # identidade ausente). Todas sao tolerada_com_residuo: o excesso exato
      # (republicacao) e capado por max_linhas_excedentes e os grupos nao-exatos
      # (contradicao de valor) por max_grupos_residuais, medidos nos 72 meses.
      tabelas:
        - nome: tab_i
          arquivo: "inf_mensal_fidc_tab_I_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (medido 72 competencias 2013-01..2018-12):
          # excess exato max 2/mes (201301), grupos residuais max 2/mes (201407).
        - nome: tab_ii
          arquivo: "inf_mensal_fidc_tab_II_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 2/mes
          # (201407), grupos residuais max 1/mes (201303).
        - nome: tab_iii
          arquivo: "inf_mensal_fidc_tab_III_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 2/mes
          # (201407), grupos residuais max 1/mes (201303).
        - nome: tab_iv
          arquivo: "inf_mensal_fidc_tab_IV_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 2/mes
          # (201407), grupos residuais max 1/mes (201303).
        - nome: tab_v
          arquivo: "inf_mensal_fidc_tab_V_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 2/mes
          # (201608), grupos residuais max 1/mes (201303).
        - nome: tab_vi
          arquivo: "inf_mensal_fidc_tab_VI_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 1/mes
          # (201307), grupos residuais max 2/mes (201608).
        - nome: tab_vii
          arquivo: "inf_mensal_fidc_tab_VII_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 1/mes
          # (201307), grupos residuais max 2/mes (201608).
        - nome: tab_ix
          arquivo: "inf_mensal_fidc_tab_IX_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 1/mes
          # (201307), grupos residuais max 2/mes (201608).
        - nome: tab_x_1
          arquivo: "inf_mensal_fidc_tab_X_1_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 5/mes
          # (201608), grupos residuais max 2/mes (201403, TAB_X_NR_COTST diverge).
        - nome: tab_x_2
          arquivo: "inf_mensal_fidc_tab_X_2_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 5/mes
          # (201608), grupos residuais max 4/mes (201608, TAB_X_QT_COTA/VL_COTA).
        - nome: tab_x_3
          arquivo: "inf_mensal_fidc_tab_X_3_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 4/mes
          # (201407), grupos residuais max 2/mes (201403, TAB_X_VL_RENTAB_MES).
        - nome: tab_x_4
          arquivo: "inf_mensal_fidc_tab_X_4_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_tp_oper, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 60
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 34/mes
          # (201608 — fundo 16.626.130 republicado byte-identico em cada par
          # tp_oper x classe_serie), grupos residuais max 2/mes (201608,
          # TAB_X_VL_TOTAL/QT_COTA).
        - nome: tab_x_5
          arquivo: "inf_mensal_fidc_tab_X_5_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 2/mes
          # (201407), grupos residuais max 1/mes (201410).
        - nome: tab_x_6
          arquivo: "inf_mensal_fidc_tab_X_6_{aaaa}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 30
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (72 competencias): excess exato max 8/mes
          # (201703), grupos residuais max 15/mes (201806). Padrao sistematico:
          # a familia Canvas/JGP (JGP Canvas, Bullseye, Special Situations, ...)
          # publica o mesmo fundo+classe+mes DUAS vezes — uma linha com
          # TAB_X_PR_DESEMP_REAL=valor e outra com '0.00' (placeholder). Nenhuma
          # coluna de identidade distingue as duas; e contradicao da fonte, nao
          # coluna de chave ausente.
    - nome: historico_2019_2020
      url: https://dados.cvm.gov.br/dados/FIDC/DOC/INF_MENSAL/DADOS/HIST/inf_mensal_fidc_{aaaa}.zip
      vigencia: { de: "201901", ate: "202010" }
      layout: zip_multi_tabela
      raw_grao: ano
      # MEDIDA (zips anuais 2019/2020): arquivos POR MES
      # (inf_mensal_fidc_tab_I_{aaaamm}.csv), 16 tabelas (I..VII + IX +
      # X_1..X_7 + X_1_1; sem VIII, sem X).
      # CORRECAO 2026-09-03: o schema desta era e o ANTIGO (CNPJ_FUNDO; nao
      # existem TP_FUNDO_CLASSE/CNPJ_FUNDO_CLASSE). Medido no header real de
      # inf_mensal_fidc_tab_I_201901.csv:
      # CNPJ_FUNDO;DENOM_SOCIAL;DT_COMPTC;CNPJ_ADMIN;ADMIN;CONDOM;...
      # Declarar a chave do schema corrente aqui fazia o gate falhar com
      # Binder "tp_fundo_classe not found" em TODAS as 16 tabelas.
      # As chaves abaixo espelham a parte historico_2013_2018 — mesmo
      # schema, medidas em 72 competencias.
      # SPLIT 2026-09-04: a parte original (201901-202212) foi dividida
      # porque o schema troca em 2020-11 — medido no zip 2020:
      # tab_I_202010.csv = schema antigo, tab_I_202011.csv = schema novo
      # (TP_FUNDO_CLASSE;CNPJ_FUNDO_CLASSE;...). Os meses 202011+ ficam na
      # parte historico_2020_2022 (schema classe).
      tabelas:
        - nome: tab_i
          arquivo: "inf_mensal_fidc_tab_I_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_ii
          arquivo: "inf_mensal_fidc_tab_II_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_iii
          arquivo: "inf_mensal_fidc_tab_III_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_iv
          arquivo: "inf_mensal_fidc_tab_IV_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_v
          arquivo: "inf_mensal_fidc_tab_V_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_vi
          arquivo: "inf_mensal_fidc_tab_VI_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_vii
          arquivo: "inf_mensal_fidc_tab_VII_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_ix
          arquivo: "inf_mensal_fidc_tab_IX_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_1
          arquivo: "inf_mensal_fidc_tab_X_1_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_1_1
          arquivo: "inf_mensal_fidc_tab_X_1_1_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          vigencia: { de: "201911" }
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_2
          arquivo: "inf_mensal_fidc_tab_X_2_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
        - nome: tab_x_3
          arquivo: "inf_mensal_fidc_tab_X_3_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_4
          arquivo: "inf_mensal_fidc_tab_X_4_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_tp_oper, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 60
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_5
          arquivo: "inf_mensal_fidc_tab_X_5_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_6
          arquivo: "inf_mensal_fidc_tab_X_6_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 30
          politica_dedup_silver: keep_first
        - nome: tab_x_7
          arquivo: "inf_mensal_fidc_tab_X_7_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc]
          vigencia: { de: "201911" }
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
    - nome: historico_2020_2022
      url: https://dados.cvm.gov.br/dados/FIDC/DOC/INF_MENSAL/DADOS/HIST/inf_mensal_fidc_{aaaa}.zip
      vigencia: { de: "202011", ate: "202212" }
      layout: zip_multi_tabela
      raw_grao: ano
      # SPLIT 2026-09-04 (medido no zip 2020): o schema troca em 2020-11 —
      # tab_I_202010.csv = schema antigo (CNPJ_FUNDO), tab_I_202011.csv =
      # schema novo (TP_FUNDO_CLASSE;CNPJ_FUNDO_CLASSE;...). Os meses
      # 202011-202212 usam o schema classe — a declaracao original da parte
      # historico_2019_2022 era correta para estes meses, errada para
      # 201901-202010. tab_i re-provado com a chave classe: excess=0 em
      # 2020-11 (1.198) e 2021-06 (1.369). X_1_1 e X_7 existem em todos os
      # meses desta parte (a fronteira 201911 so afeta 2019).
      tabelas:
        - nome: tab_i
          arquivo: "inf_mensal_fidc_tab_I_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_ii
          arquivo: "inf_mensal_fidc_tab_II_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_iii
          arquivo: "inf_mensal_fidc_tab_III_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_iv
          arquivo: "inf_mensal_fidc_tab_IV_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_v
          arquivo: "inf_mensal_fidc_tab_V_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_vi
          arquivo: "inf_mensal_fidc_tab_VI_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_vii
          arquivo: "inf_mensal_fidc_tab_VII_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_ix
          arquivo: "inf_mensal_fidc_tab_IX_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_x_1
          arquivo: "inf_mensal_fidc_tab_X_1_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_1_1
          arquivo: "inf_mensal_fidc_tab_X_1_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_x_2
          arquivo: "inf_mensal_fidc_tab_X_2_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
        - nome: tab_x_3
          arquivo: "inf_mensal_fidc_tab_X_3_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_4
          arquivo: "inf_mensal_fidc_tab_X_4_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_tp_oper, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 60
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
        - nome: tab_x_5
          arquivo: "inf_mensal_fidc_tab_X_5_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_x_6
          arquivo: "inf_mensal_fidc_tab_X_6_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 30
          politica_dedup_silver: keep_first
        - nome: tab_x_7
          arquivo: "inf_mensal_fidc_tab_X_7_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
    - nome: historico_2023_2024_early
      url: https://dados.cvm.gov.br/dados/FIDC/DOC/INF_MENSAL/DADOS/HIST/inf_mensal_fidc_{aaaa}.zip
      vigencia: { de: "202301", ate: "202309" }
      layout: zip_multi_tabela
      raw_grao: ano
      # MEDIDA (zip anual 2023): Jan--Sep use a hybrid schema. The five
      # TAB_X_* files below expose CNPJ_FUNDO + TAB_X_CLASSE_SERIE (and
      # TAB_X_TP_OPER for X_4), while the other 11 files already use the
      # TP_FUNDO_CLASSE/CNPJ_FUNDO_CLASSE columns. October is the measured
      # boundary where all files use the class schema and TAB_X appears.
      # Key probes over Jan--Sep 2023 found 0 excess rows in every table;
      # the five hybrid keys are therefore explicitly verificada below.
      tabelas:
        - nome: tab_i
          arquivo: "inf_mensal_fidc_tab_I_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_ii
          arquivo: "inf_mensal_fidc_tab_II_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_iii
          arquivo: "inf_mensal_fidc_tab_III_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_iv
          arquivo: "inf_mensal_fidc_tab_IV_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_v
          arquivo: "inf_mensal_fidc_tab_V_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_vi
          arquivo: "inf_mensal_fidc_tab_VI_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_vii
          arquivo: "inf_mensal_fidc_tab_VII_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_ix
          arquivo: "inf_mensal_fidc_tab_IX_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_x_1
          arquivo: "inf_mensal_fidc_tab_X_1_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: verificada
        - nome: tab_x_1_1
          arquivo: "inf_mensal_fidc_tab_X_1_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_x_2
          arquivo: "inf_mensal_fidc_tab_X_2_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: verificada
        - nome: tab_x_3
          arquivo: "inf_mensal_fidc_tab_X_3_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: verificada
        - nome: tab_x_4
          arquivo: "inf_mensal_fidc_tab_X_4_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_tp_oper, tab_x_classe_serie]
          chave_status: verificada
        - nome: tab_x_5
          arquivo: "inf_mensal_fidc_tab_X_5_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
        - nome: tab_x_6
          arquivo: "inf_mensal_fidc_tab_X_6_{aaaamm}.csv"
          chave: [cnpj_fundo, dt_comptc, tab_x_classe_serie]
          chave_status: verificada
        - nome: tab_x_7
          arquivo: "inf_mensal_fidc_tab_X_7_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          chave_status: verificada
    - nome: historico_2023_2024
      url: https://dados.cvm.gov.br/dados/FIDC/DOC/INF_MENSAL/DADOS/HIST/inf_mensal_fidc_{aaaa}.zip
      vigencia: { de: "202310", ate: "202412" }
      layout: zip_multi_tabela
      raw_grao: ano
      # MEDIDA (zips anuais 2023/2024): de 202310 em diante ha 17 arquivos
      # por competencia (I..VII + IX + X + X_1..X_7; sem VIII), todos no
      # schema TP_FUNDO_CLASSE/CNPJ_FUNDO_CLASSE. A fronteira 202310 e a
      # complementar da parte historico_2023_2024_early acima.
      tabelas:
        - nome: tab_i
          arquivo: "inf_mensal_fidc_tab_I_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_ii
          arquivo: "inf_mensal_fidc_tab_II_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_iii
          arquivo: "inf_mensal_fidc_tab_III_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_iv
          arquivo: "inf_mensal_fidc_tab_IV_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_v
          arquivo: "inf_mensal_fidc_tab_V_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_vi
          arquivo: "inf_mensal_fidc_tab_VI_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_vii
          arquivo: "inf_mensal_fidc_tab_VII_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_ix
          arquivo: "inf_mensal_fidc_tab_IX_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_x
          arquivo: "inf_mensal_fidc_tab_X_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          vigencia: { de: "202310" }
        - nome: tab_x_1
          arquivo: "inf_mensal_fidc_tab_X_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_classe_serie, id_subclasse]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 100
          max_grupos_residuais: 50
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [id_subclasse]
          # TOLERADA_COM_RESIDUO (sweep completo 202310-202412, 15 meses):
          # maximos em 202310 = 114 excess totais, 63 excess exatos e 46
          # grupos residuais; os residuais variam somente TAB_X_NR_COTST.
          # Caps 100/50. De 202406 em diante todos fecharam em 0.
        - nome: tab_x_1_1
          arquivo: "inf_mensal_fidc_tab_X_1_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_x_2
          arquivo: "inf_mensal_fidc_tab_X_2_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 100
          max_grupos_residuais: 20
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep completo 202310-202412, 15 meses):
          # maximo exato=68 excess (202310); maximo residual=16 grupos
          # (202311), variando somente TAB_X_QT_COTA/TAB_X_VL_COTA. A
          # republicacao local atual de 202409 tem 1 grupo residual, nao exato.
        - nome: tab_x_3
          arquivo: "inf_mensal_fidc_tab_X_3_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 50
          max_grupos_residuais: 20
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep completo 202310-202412, 15 meses):
          # maximos em 202311 = 52 excess totais, 34 excess exatos e 15
          # grupos residuais, variando somente TAB_X_VL_RENTAB_MES.
        - nome: tab_x_4
          arquivo: "inf_mensal_fidc_tab_X_4_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_tp_oper, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 150
          max_grupos_residuais: 15
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep 202310-202412, 15 meses, downloads
          # atuais de 2026-09): maximo exato=119 excess em 202401 (152 totais,
          # 120 grupos, 119 exatos + 1 residual); maximo residual=9 grupos em
          # 202310 (99 exatos). 202406-202408 fecharam em 0; 202409 tem 3+1,
          # 202412 0+1. Residuais variam somente TAB_X_VL_TOTAL/TAB_X_QT_COTA.
          # O cap 5/5 anterior vinha de medicao representativa e estourou.
          # Caps 150/15.
        - nome: tab_x_5
          arquivo: "inf_mensal_fidc_tab_X_5_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
        - nome: tab_x_6
          arquivo: "inf_mensal_fidc_tab_X_6_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tab_x_classe_serie]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 50
          max_grupos_residuais: 20
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep completo 202310-202412, 15 meses):
          # maximos em 202311 = 50 excess totais, 31 excess exatos e 15
          # grupos residuais; TAB_X_PR_DESEMP_REAL/ESPERADO variam. 202406
          # tem 1 grupo exato, mas a parte inteira nao pode ser tolerada.
        - nome: tab_x_7
          arquivo: "inf_mensal_fidc_tab_X_7_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]

# ────────────────────────────────────────────────────────────
# cda_fi — shape D (layout temporal hibrido)
#
# VERIFICADO empiricamente nesta sessao (zips reais baixados e abertos):
#   - DADOS/ tem zips mensais a partir de 202301 (cda_fi_202301.zip)
#   - DADOS/HIST/ tem zips ANUAIS ate 2022 (cda_fi_2022.zip) com arquivos
#     POR ANO (cda_fiim_2022.csv), nao por mes, e cada arquivo carrega os
#     12 DT_COMPTC do ano inteiro — ver "era historico" abaixo
#   - cada zip mensal contem 10 arquivos por competencia (cda_fiim +
#     cda_fi_BLC_1..8 + cda_fi_PL)
#   - do arquivo de fiim o nome muda na virada 202401→202402: cda_fiim_*
#     passa a cda_fie_* (esquema _CLASSE permanece)
#
# TRES ERAS DE ESQUEMA (corrigem o erro {tp_fundo_classe} vs {tp_fundo}):
#   corrente_2023  202301..202311  TP_FUNDO-era (sem "_CLASSE" nas colunas).
#                                  Chaves medidas nesta sessao contra zips
#                                  reais de 202301 e 202311.
#   corrente_2024  202312..202401  TP_FUNDO_CLASSE-era. Chaves medidas contra
#                                  202312 e 202401.
#   corrente_202402 202402 em diante  nome de fiim vira cda_fie_
#
# Era historico (<= 202212) NAO e modelada: os zips anuais trazem arquivos
# por ANO com todos os 12 meses misturados dentro de cada CSV — nao ha como
# escrever um partition de competencia mensal sem um filtro por DT_COMPTC,
# e o mecanismo de grao por linha nao existe. Declara-la aqui faria rule 1
# (arquivos nao declarados) ou pior, linhas do ano inteiro dentro de um
# unico partition de mes — o padrao de corrupcao que o catalogo v2 existe
# para impedir. Entao fica de fora, e competencias <= 202212 falham alto
# (0 parte casa) ate uma decisao de desenho real (ex.: fila mensal deduzida
# por DT_COMPTC) virar codigo. fidc_inf_mensal e diferente: os zips HIST
# dela trazem arquivos POR MES (inf_mensal_fidc_tab_*_202401.csv), por isso
# aquela entrada modela o historico normalmente.
#
# Chaves verificadas nesta sessao (202301/202311/202312/202401 baixados e
# medidos, alem dos 202603-202605 ja medidos):
#   - blc_1/blc_4/blc_8: TP_NEGOC completa a chave em TODAS as eras (schema
#     tem TP_NEGOC desde 202301) — 0 duplicatas.
#   - blc_7: chave real precisa de CD_BV_MERC + CD_PAIS + DT_VENC + EMISSOR
#     alem de CD_ATIVO_BV_MERC + DS_ATIVO_EXTERIOR — 0 duplicatas em 7
#     competencias. era PENDENTE em todas as partes antes desta medicao.
#   - blc_2/blc_3/pl: ja eram 0 na era TP_FUNDO; promovidos a verificada.
#   - blc_5/blc_6: a chave e o perfil de remuneracao por emissao
#     (PR_CUPOM_POSFX/PR_TAXA_PREFX/PR_INDEXADOR_POSFX/CD_INDEXADOR_POSFX,
#     com TITULO_CETIP/TITULO_GARANTIA/TP_NEGOC adicionais no blc_6) —
#     hypothesis confirmada: o mesmo emissor+vencimento tem UM registro por
#     lote/remuneracao. excess=0 em 6/7 competencias (blc_5, 202301 deixa 2
#     linhas-irredutiveis) e em todas as 7 (blc_6). Ver comentarios.
# Ainda PENDENTE (nao ha chave real): fiim — ver comentarios por tabela.
# ────────────────────────────────────────────────────────────
- id: cda_fi
  fonte: cvm
  dominio: fundos
  periodicidade: mensal
  grao_competencia: mes
  encoding: cp1252
  sep: ";"
  snapshot: false
  restatement: true
  partes:
    - nome: historico_0506
      url: https://dados.cvm.gov.br/dados/FI/DOC/CDA/DADOS/HIST/cda_fi_{aaaa}.zip
      vigencia: { de: "200501", ate: "200612" }
      layout: zip_multi_tabela
      filtro_linha: DT_COMPTC
      raw_grao: ano
      # MEDIDA (zip anual 2005/2006): 6 membros POR ANO (BLC_1,2,3,4,8 + PL,
      # sem fiim), cada CSV com os 12 DT_COMPTC do ano. Schema TP_FUNDO-era
      # (TP_FUNDO/CNPJ_FUNDO, sem _CLASSE), headers identicos ao corrente_2023.
      # Chaves medidas nesta sessao (probe com filtro_linha, split por
      # DT_COMPTC, contra os zips anuais 2005 e 2006, 24 meses): blc_1/2/3/8
      # VERIFICADA (0 excess), blc_4 TOLERADA (6 linhas byte-identicas em 2005
      # — republicacao CVM). Ver comentarios por tabela.
      tabelas:
        - nome: blc_1
          arquivo: "cda_fi_BLC_1_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_isin, dt_venc, tp_negoc]
          # VERIFICADA: chave espelha corrente_2023 (TP_NEGOC incluido).
          # excess=0 em 200512 (17,324) e 200606 (17,561) e em todos os 24
          # meses de 2005+2006; null-rate 0% em toda coluna-chave.
        - nome: blc_2
          arquivo: "cda_fi_BLC_2_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cnpj_fundo_cota, tp_negoc]
          # VERIFICADA: TP_NEGOC e o separador real da posicao em cota de
          # fundo ("Mantido ate o vencimento" vs "Para negociacao" — mesma
          # cota, dois lotes). Sem tp_negoc, excess=1/mes em 2005 (jan-mai).
          # excess=0 em 200512 (17,003) e 200606 (19,319); tp_negoc 0% null
          # nesta era (populada).
        - nome: blc_3
          arquivo: "cda_fi_BLC_3_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_swap, tp_negoc]
          # VERIFICADA: mesmo TP_NEGOC do blc_2 (swap mantido vs negociado).
          # Sem tp_negoc, excess=1 em 200507/200509/200609. excess=0 em
          # 200512 (845) e 200606 (909); tp_negoc 0% null nesta era.
        - nome: blc_4
          arquivo: "cda_fi_BLC_4_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo, tp_negoc, dt_ini_vigencia]
          chave_status: tolerada
          max_linhas_excedentes: 20
          politica_dedup_silver: keep_first
          # TOLERADA (byte-identica): DT_INI_VIGENCIA separa tranches do mesmo
          # titulo (mesmo CD_ISIN, datas de emissao distintas — ex. CPEL14).
          # CD_ISIN sai da chave (null estrutural p/ futuros, ~6,4% em 200812,
          # e redundante dado cd_ativo+dt_ini_vigencia). Sobram 6 linhas
          # byte-identicas em 2005 (200502:2, 200503/506/509/511:1 cada),
          # 0 em 2006/2008/2014 — republicacao CVM de um lote de futuro.
        - nome: blc_8
          arquivo: "cda_fi_BLC_8_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, ds_ativo, tp_negoc]
          chaves_permitem_nulos: [cpf_cnpj_emissor]
          # VERIFICADA: chave espelha corrente_2023 (cpf_cnpj_emissor na chave,
          # whitelisted). excess=0 em 200512 (41,554) e 200606 (42,194).
          # CPF_CNPJ_EMISSOR null ~53% a ~100% conforme o mes/ano — emissor
          # sem CNPJ brasileiro (posicoes operacionais, derivativos de bolsa,
          # emissores offshore), mesmo padrao estrutural da era corrente.
        - nome: pl
          arquivo: "cda_fi_PL_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc]
          # VERIFICADA (probe com filtro_linha, split por DT_COMPTC contra o
          # zip anual): excess=0 em 200812 (8,354) e 202212 (25,397) — um PL
          # por fundo por data, como construcao.
    - nome: historico_0717
      url: https://dados.cvm.gov.br/dados/FI/DOC/CDA/DADOS/HIST/cda_fi_{aaaa}.zip
      vigencia: { de: "200701", ate: "201712" }
      layout: zip_multi_tabela
      filtro_linha: DT_COMPTC
      raw_grao: ano
      # MEDIDA (zip anual 2008/2014): 9 membros POR ANO (BLC_1..8 + PL, sem
      # fiim). pl VERIFICADA. blc_1/3/4/6/7/8 VERIFICADA, blc_2 VERIFICADA com
      # tp_negoc whitelisted (100% null a partir de 2008), blc_5
      # TOLERADA_COM_RESIDUO (residuo lot-level, 2 grupos/mes em 2014). Ver
      # comentarios por tabela.
      tabelas:
        - nome: blc_1
          arquivo: "cda_fi_BLC_1_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_isin, dt_venc, tp_negoc]
          # VERIFICADA: excess=0 em 200812 (18,344) e 201406 (24,662) e em
          # todos os 24 meses de 2008+2014; null-rate 0% em toda coluna-chave
          # (TP_NEGOC segue populada nesta tabela ao contrario do blc_2/3).
        - nome: blc_2
          arquivo: "cda_fi_BLC_2_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cnpj_fundo_cota, tp_negoc]
          chaves_permitem_nulos: [tp_negoc]
          # VERIFICADA: TP_NEGOC separa "Mantido ate o vencimento" vs "Para
          # negociacao" (ver historico_0506), mas a CVM deixou de popular a
          # coluna a partir de 2008 — 100% null em 2008/2014 (0% null em
          # 2005/2006). Whitelisted para o gate de null-rate nao falhar os
          # anos vazios; a chave segue usando a coluna onde ela e populada.
          # excess=0 em 200812 (29,010) e 201406 (64,526).
        - nome: blc_3
          arquivo: "cda_fi_BLC_3_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_swap, tp_negoc]
          chaves_permitem_nulos: [tp_negoc]
          # VERIFICADA: mesmo TP_NEGOC do blc_2 — 100% null a partir de 2008,
          # whitelisted. excess=0 em 200812 (432) e 201406 (371).
        - nome: blc_4
          arquivo: "cda_fi_BLC_4_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo, tp_negoc, dt_ini_vigencia]
          chave_status: tolerada
          max_linhas_excedentes: 20
          politica_dedup_silver: keep_first
          # TOLERADA (2026-09-03): era VERIFICADA por extrapolacao — medida
          # apenas em 2008+2014. Medido em 201104: excess=17 em 17 grupos,
          # TODOS byte-identicos, 0 grupos nao-exatos (republicacao da CVM,
          # nao contradicao de fonte). Mesma chave do historico_0506
          # (dt_ini_vigencia separa tranches; cd_isin fora por ser null em
          # futuros). excess=0 em 200812 (49,734) e 201406 (52,269).
        - nome: blc_5
          arquivo: "cda_fi_BLC_5_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx, tp_negoc]
          dt_linha_desde: "2007-06-01"
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # DT_LINHA_DESDE 2007-06 (medido no zip anual 2007): BLC_5 so tem
          # linhas a partir de 2007-06 (3 linhas em jun/jul, 24 em ago, ~9k
          # de setembro em diante). Os meses anteriores nao existem no
          # arquivo — o post-split falhava com "got []". CVM implementou
          # esse bloco no meio de 2007.
          # TOLERADA_COM_RESIDUO: chave-perfil de remuneracao (mesma do
          # corrente_2023) + TP_NEGOC. O residuo e posicao por LOTE — o mesmo
          # emissor+vencimento+perfil em dois lotes que so diferem em
          # QT_POS_FINAL/VL_MERC_POS_FINAL (ex. Votorantim DI 101,4%: 200 vs
          # 500 unidades). 0 grupos exatos; residuo de 2 grupos/mes em todos
          # os 12 meses de 2014 e 3 grupos esparsos em 2008. Colunas de taxa
          # whitelisted (PR_TAXA_PREFX ~95-99% null, demais 3-9%).
        - nome: blc_6
          arquivo: "cda_fi_BLC_6_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx, titulo_cetip, titulo_garantia, tp_negoc]
          dt_linha_desde: "2007-08-01"
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # DT_LINHA_DESDE 2007-08 (medido no zip anual 2007): BLC_6 so tem
          # linhas a partir de 2007-08 (2 linhas em ago, ~4.6k em setembro).
          # Mesma entrada em vigor escalonada do BLC_5.
          # VERIFICADA: chave-perfil + cetip/garantia/tp_negoc (espelha
          # corrente_2023). excess=0 em 200812 (5,818) e 201406 (20,174) e nos
          # 24 meses de 2008+2014. Colunas de taxa whitelisted (PR_TAXA_PREFX
          # ~96-99% null, demais 5-9%); cpf_cnpj_emissor 0% null aqui.
        - nome: blc_7
          arquivo: "cda_fi_BLC_7_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo_bv_merc, ds_ativo_exterior, cd_bv_merc, cd_pais, dt_venc, emissor, tp_negoc]
          dt_linha_desde: "2007-09-01"
          chaves_permitem_nulos: [ds_ativo_exterior, dt_venc, emissor]
          # TP_NEGOC adicionado a chave (2026-09-03): medido em 201510 — 1
          # grupo nao-exato onde TP_NEGOC varia ("Mantido ate o vencimento"
          # vs "Para negociacao", mesma posicao em dois modos de negociacao).
          # Re-provado com tp_negoc: excess=0 em 201510, 201511 e 201706.
          # DT_LINHA_DESDE 2007-09 (medido no zip 2007): BLC_7 so tem linhas
          # a partir de 2007-09 (93 linhas; o arquivo todo tem 209).
          # VERIFICADA: chave completa do corrente_2023 (CD_BV_MERC+CD_PAIS+
          # DT_VENC+EMISSOR), com emissor a mais no whitelist — EMISSOR null
          # ~9,5-19% (posicao identificada so por CD_BV_MERC/BV_MERC, sem nome
          # de emissor). excess=0 em 200812 (58) e 201406 (1,842). DT_VENC null
          # 43-59% (ativo sem vencimento fixo) e DS_ATIVO_EXTERIOR 100% null
          # na era HIST — ambos whitelisted.
        - nome: blc_8
          arquivo: "cda_fi_BLC_8_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, ds_ativo, tp_negoc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [cpf_cnpj_emissor]
          # TOLERADA (2026-09-04): era VERIFICADA por extrapolacao (2008+2014).
          # O re-run com erros completos revelou: em 201104, excess=2 em 2
          # grupos, TODOS byte-identicos (republicacao da CVM) — a truncagem
          # de 300 caracteres do primeiro run mostrava so a falha do blc_4.
          # VERIFICADA: excess=0 em 200812 (43,997) e 201406 (90,175).
          # CPF_CNPJ_EMISSOR null ~53-100% conforme o mes/ano (ver
          # historico_0506) - whitelisted. Sem cpf_cnpj_emissor na chave,
          # excess=5 (200812) e 22 (201406): a coluna e necessaria.
        - nome: pl
          arquivo: "cda_fi_PL_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc]
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (2026-09-04): era VERIFICADA; o re-run revelou em 201104
          # excess=1, byte-identico (mesma republicacao do blc_8).
          # VERIFICADA (probe com filtro_linha, split por DT_COMPTC contra o
          # zip anual): excess=0 em 200812 (8,354) e 202212 (25,397) - um PL
          # por fundo por data, como construcao.
    - nome: historico_1822
      url: https://dados.cvm.gov.br/dados/FI/DOC/CDA/DADOS/HIST/cda_fi_{aaaa}.zip
      vigencia: { de: "201801", ate: "202212" }
      layout: zip_multi_tabela
      filtro_linha: DT_COMPTC
      raw_grao: ano
      # MEDIDA (capturas anuais 2018/2022): 10 membros POR ANO (BLC_1..8 + PL +
      # fiim). A CVM depois retirou cda_fiim_2018.csv: o member-set publico atual
      # de 2018 tem 9 membros. Bronze segue o ultimo download; fiim inicia em
      # 2019-01 (vigencia + dt_linha_desde). Chaves medidas nesta
      # sessao (2026-08-25, probe com split por DT_COMPTC contra os zips 2018
      # e 2022): 8 VERIFICADA (excess=0 em >=2 competencias), fiim
      # TOLERADA_COM_RESIDUO (1 grupo residual de lote). pl VERIFICADA.
      tabelas:
        - nome: fiim
          arquivo: "cda_fiim_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor, tp_negoc, dt_ini_vigencia, cd_selic, id_doc]
          vigencia: { de: "201901" }
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor, tp_negoc, dt_ini_vigencia, cd_selic]
          # O zip publico atual nao carrega cda_fiim_2018.csv. vigencia impede
          # que o unpacker exija o membro antes de 2019; dt_linha_desde mantem
          # a mesma fronteira no split por linha e no silver.
          dt_linha_desde: "2019-01-01"
          # TOLERADA_COM_RESIDUO (medido 2026-08-25, zips 2018/2022, split por
          # DT_COMPTC): a chave base de 11 colunas (mesma da corrente_2023)
          # deixa 8 grupos residuais em 201812 — todos de fundos de indice
          # (ETFs) carregando LFT CD_ATIVO=210100 em multiplas series. Fechado
          # somando DT_INI_VIGENCIA (serie/vencimento do titulo publico — o
          # mesmo LFT em datas 2019..2023 e ativos distintos), CD_SELIC (codigo
          # Selic do titulo — separa series NTN-B com mesmo DT_VENC, ex. IRF-M
          # P2 CD_SELIC 100000 vs 950199) e ID_DOC (identificador do documento
          # de declaracao — separa fundo com 2 documentos no mesmo mes, ex.
          # MIRAE 202206 ID_DOC 322354/322376). excess=0 em 201806/201812;
          # 1 grupo residual em 202206 e 202212 (HASHDEX CRYPTO METAVERSE,
          # CD_ATIVO="META 11 CLA", EMISSOR="HASHDEX META 11", DT_VENC
          # 2050-12-31: 2 lotes do mesmo ativo com QT_POS_FINAL/VL_MERC_POS_FINAL
          # distintos — posicao por LOTE, residuo e a regra, nao excecao; nenhuma
          # coluna separa os 2 lotes). exact_dup_groups=0 em toda medicao.
          # Colunas estruturais NULL (whitelisted): em 2018 o fiim e quase
          # inteiro titulo publico (TP_ATIVO/DS_ATIVO/DT_VENC/CD_SELIC 100%
          # NULL — CD_ATIVO+DT_INI_VIGENCIA carregam a identidade); em 2022
          # diversifica (CD_ATIVO 14.7% NULL, EMISSOR 85.5%, CPF_CNPJ_EMISSOR
          # 92.9%, DT_VENC 89.2%, DS_ATIVO 90.5% — ativo sem codigo publico;
          # TP_NEGOC 1.71% NULL). TP_APLIC/TP_FUNDO/CNPJ_FUNDO/DT_COMPTC/ID_DOC
          # sempre preenchidos.
        - nome: blc_1
          arquivo: "cda_fi_BLC_1_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_isin, dt_venc, tp_negoc]
          # VERIFICADA (probe com split por DT_COMPTC): excess=0 em 201812
          # (30,908) e 202212 (40,696). Chave da corrente_2023 (TP_FUNDO era,
          # mesmo schema) — TP_NEGOC completa a chave como naquela parte.
        - nome: blc_2
          arquivo: "cda_fi_BLC_2_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cnpj_fundo_cota]
          # VERIFICADA (probe com split por DT_COMPTC): excess=0 em 201812
          # (89,569) e 202212 (184,837). CNPJ_FUNDO_COTA identifica a cota —
          # mesmo achado da corrente_2023.
        - nome: blc_3
          arquivo: "cda_fi_BLC_3_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_swap]
          # VERIFICADA (probe com split por DT_COMPTC): excess=0 em 201812
          # (195) e 202212 (305).
        - nome: blc_4
          arquivo: "cda_fi_BLC_4_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo, cd_isin, tp_negoc, ds_ativo, dt_ini_vigencia]
          chaves_permitem_nulos: [cd_isin]
          # DS_ATIVO entra na chave (2026-09-03, medido em 2020-07): a
          # chave de 8 colunas deixa excess=22 em 22 grupos, todos nao-exatos,
          # com DS_ATIVO variando em 22/22 (mesma posicao — ex. SAPR4 com
          # qt/vl identicos — descrita como "SANEPAR      PN      N2" e
          # "SANEPAR PN"). DT_INI_VIGENCIA entra tambem (2026-09-04, medido
          # em 2021-10): com ds_ativo so, excess=16/16 grupos com
          # dt_ini_vigencia variando; com as duas, excess=0 em 134.933.
          # Re-provado com as duas: excess=0 em 2020-07 (99.616) e 2021-10.
          # VERIFICADA (probe com split por DT_COMPTC): excess=0 em 201812
          # (53,254) e 202212 (180,295). CD_ISIN whitelisted: vazio em
          # 1.10-1.19% das linhas em 2018 (585-618 linhas/mes) e ~0% em 2022 —
          # futuros DI1/DDI nao carregam ISIN (verificado por TP_ATIVO: 521
          # "Futuro de DI1" + 63 "Futuro de DDI" em 201812); na corrente_2023
          # ficava abaixo do limiar, aqui estourou por 0.1-0.2 p.p.
        - nome: blc_5
          arquivo: "cda_fi_BLC_5_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx, tp_negoc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # TOLERADA_COM_RESIDUO (2026-09-03): nao declarava chave_status,
          # portanto valia VERIFICADA e qualquer excesso falhava duro. Medido
          # em 2022-03: excess=1, 1 grupo nao-exato, variando apenas em
          # qt_aquis/vl_aquis/qt_pos_final/vl_merc_pos_final — a categoria
          # ja conhecida de posicao por LOTE (mesmo perfil de remuneracao em
          # dois lotes), igual ao blc_5 da parte historico_0717.
          # VERIFICADA (probe com split por DT_COMPTC): excess=0 em 201806,
          # 201812, 202206 e 202212 (53,530 em 202212). Chave-perfil de
          # remuneracao da corrente_2023 + TP_NEGOC: sem tp_negoc sobravam 3
          # grupos em 201812 (TP_NEGOC variando em 100% dos grupos); com
          # tp_negoc fecha. Colunas de taxa em chaves_permitem_nulos
          # (PR_TAXA_PREFX ~95-96% NULL, demais 3-9%).
        - nome: blc_6
          arquivo: "cda_fi_BLC_6_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx, titulo_cetip, titulo_garantia, tp_negoc]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # VERIFICADA (probe com split por DT_COMPTC): excess=0 em 201812
          # (30,263) e 202212 (9,882). Chave-perfil + cetip/garantia/tp_negoc
          # (ver corrente_2023). Colunas de taxa em chaves_permitem_nulos
          # (PR_TAXA_PREFX ~97-100% NULL).
        - nome: blc_7
          arquivo: "cda_fi_BLC_7_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo_bv_merc, ds_ativo_exterior, cd_bv_merc, cd_pais, dt_venc, emissor, tp_negoc]
          chaves_permitem_nulos: [ds_ativo_exterior, dt_venc, emissor]
          # TP_NEGOC adicionado a chave (2026-09-04, medido em 2020-05): a
          # chave de 11 colunas deixa excess=1; com tp_negoc, excess=0 em
          # 19.944 linhas. Mesmo fix do blc_7 da parte historico_0717.
          # EMISSOR whitelisted (2026-09-03): medido em 2018-01, EMISSOR tem
          # 1.09% de nulos — acima do limiar de 1% do gate de null-rate, e a
          # coluna e de chave. Em 201803-05 fica em 0.72-0.76% (abaixo), daí
          # a falha intermitente. A parte historico_0717 ja whitelista EMISSOR
          # (9,5-19% nulos) pelo mesmo motivo: a posicao e identificada por
          # CD_BV_MERC/BV_MERC quando nao ha nome de emissor.
          # VERIFICADA (probe com split por DT_COMPTC): excess=0 em 201812
          # (14,417) e 202212 (49,088). Chave completa da corrente_2023
          # (CD_BV_MERC+CD_PAIS+DT_VENC+EMISSOR). DS_ATIVO_EXTERIOR vazio em
          # ~17-19%, DT_VENC em ~8-9% (ver corrente_2023 para o racional).
        - nome: blc_8
          arquivo: "cda_fi_BLC_8_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, ds_ativo, tp_negoc]
          chaves_permitem_nulos: [cpf_cnpj_emissor]
          # VERIFICADA (probe com split por DT_COMPTC): excess=0 em 201812
          # (97,380) e 202212 (194,627). CPF_CNPJ_EMISSOR vazio em ~61-80%
          # (ver corrente_2023 para o racional — emissor sem CPF/CNPJ BR).
        - nome: pl
          arquivo: "cda_fi_PL_{aaaa}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc]
          # VERIFICADA (probe com filtro_linha, split por DT_COMPTC contra o
          # zip anual): excess=0 em 200812 (8,354) e 202212 (25,397) — um PL
          # por fundo por data, como construcao.
    - nome: corrente_2023
      url: https://dados.cvm.gov.br/dados/FI/DOC/CDA/DADOS/cda_fi_{aaaamm}.zip
      vigencia: { de: "202301", ate: "202311" }
      layout: zip_multi_tabela
      tabelas:
        - nome: fiim
          arquivo: "cda_fiim_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor, tp_negoc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 15
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor]
          # TOLERADA_COM_RESIDUO (re-medido 2026-08, zips reais 202301/202311):
          # excess=10 em 202301 (4,467) e 2 em 202311 (4,683); 0 grupos
          # exatos, 3 e 2 grupos residuais nao-exatos. DECISAO DE DOMINIO
          # (usuario, 2026-08-20): FIIM/FIE carrega uma posicao por LOTE, nao
          # por ativo — o mesmo titulo negociado em momentos diferentes tem
          # agio/deságio proprio e portanto valor diferente na mesma
          # competencia (ex.: mesmo emissor/vencimento/tipo, dois lotes com
          # taxas efetivas distintas). Residuo e a regra, nao excecao.
          # Confirmado nos 3 grupos de 202301: nenhum e duplicata — todos tem
          # QT_POS_FINAL/VL_MERC_POS_FINAL genuinamente diferentes entre as
          # linhas do mesmo grupo (ex.: fundo 45.823.821/0001-66, CD_ATIVO
          # "210100", 8 linhas de 743 a 3.838 unidades — a soma das 8 bate
          # 99,99% do VL_PATRIM_LIQ do fundo, R$272,55mi vs R$272,52mi — se
          # fosse duplicata a soma estouraria o PL). excess_excl_null_keys=0
          # em toda medicao: o residuo so aparece onde colunas da propria
          # chave sao NULL. NULL nao e confidencialidade temporaria (DT_CONFID_APLIC,
          # ~3 meses apos dt_comptc, ja modelada pela tabela fie_confid/confid
          # separada) — e estrutural: ativo ilíquido/privado sem codigo
          # publico catalogado pela CVM (ex.: lote imobiliario so com
          # CD_ATIVO de registro, sem TP_ATIVO/DS_ATIVO/EMISSOR). Whitelisted
          # com % medido em 202301: tp_ativo 5,7%, cd_ativo 13,2%, ds_ativo
          # 90,1%, dt_venc 89,4%, cpf_cnpj_emissor 94,4%, emissor 86,9%. Cap
          # excesso exato 20 (medido 0 — exact_dup_groups=0 em toda
          # competencia medida, nunca houve duplicata byte-identica aqui).
          # Cap grupos residuais 15 (~5x o maximo desta era, 3) — ver
          # corrente_202402 para o cap desta era mais ativa (ate 238 grupos).
          # Cada grupo residual vai para _residuos.json.
        - nome: blc_1
          arquivo: "cda_fi_BLC_1_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_isin, dt_venc, tp_negoc]
          # VERIFICADA: chave 7-colunas sem tp_negoc tinha excess=170 (202301)
          # e 151 (202311), TP_NEGOC variando em 100% dos grupos. Com
          # tp_negoc: excess=0 em 202301 e 202311 (TP_FUNDO-era schema tem
          # TP_NEGOC — fix vale tambem nesta era).
        - nome: blc_2
          arquivo: "cda_fi_BLC_2_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cnpj_fundo_cota]
          # VERIFICADA: excess=0 em 202301 (182,884) e 202311.
        - nome: blc_3
          arquivo: "cda_fi_BLC_3_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_swap]
          # VERIFICADA: excess=0 em 202301 (308) e 202311.
        - nome: blc_4
          arquivo: "cda_fi_BLC_4_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo, cd_isin, tp_negoc]
          # VERIFICADA: chave 7-colunas sem tp_negoc tinha excess=1 em 202301
          # (TP_NEGOC variando no grupo); com tp_negoc, excess=0 em 202301 e
          # 202311.
        - nome: blc_5
          arquivo: "cda_fi_BLC_5_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep 202301-202311, 11 zips no servidor,
          # downloads atuais de 2026-09): maximo=3 grupos residuais em 202303
          # (3 excess, 0 exatos); 202311 fechou em 0. Nenhum grupo e
          # byte-identico em nenhum mes — os residuais variam TP_NEGOC/
          # QT_POS_FINAL/VL_MERC_POS_FINAL (mais colunas de negociacao
          # QT/VL_AQUIS_NEGOC, QT/VL_VENDA_NEGOC): mesma posicao reportada com
          # splits de negociacao distintos, contradicao da fonte, nao
          # republicacao. +tp_negoc/+titulo_posfx nao fecham (testado em
          # 202301: sobram grupos). Caps 5/5.
          # A chave continua o "perfil de remuneracao" por emissao (lotes com
          # cupons/agios distintos). Colunas de taxa em chaves_permitem_nulos:
          # PR_TAXA_PREFX ~90% NULL (titulo pos-fixado nao tem), as demais
          # 3-6% NULL — dimensao gatilho da chave, nao podem ser obrigadas.
        - nome: blc_6
          arquivo: "cda_fi_BLC_6_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx, titulo_cetip, titulo_garantia, tp_negoc]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # VERIFICADA: mesma chave-perfil de blc_5 (cupom/agio/indexador),
          # acrescida das colunas cetip/garantia/tp_negoc que separam emissos
          # com mesmo perfil. Probe excess=0 em TODAS as 7 competencias: 202301
          # (8,636), 202311, 202312 (11,486), 202401 (9,793), 202603 (14,677),
          # 202604 (11,936), 202605 (2,257). Candidata menor (ratefull+idx sem
          # cetip/gar/negoc) fechava o moderno mas deixava 2-3 nas eras
          # 202312/202401 — TP_NEGOC/TITULO_CETIP/TITULO_GARANTIA variando.
          # Colunas de taxa em chaves_permitem_nulos (PR_TAXA_PREFX ~90% NULL).
        - nome: blc_7
          arquivo: "cda_fi_BLC_7_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cd_ativo_bv_merc, ds_ativo_exterior, cd_bv_merc, cd_pais, dt_venc, emissor]
          chaves_permitem_nulos: [ds_ativo_exterior, dt_venc, emissor]
          # VERIFICADA: chave antiga (cd_ativo_bv_merc, ds_ativo_exterior)
          # tinha excess=2,080 (202301) e 1,820 (202311). Chave completa com
          # CD_BV_MERC+CD_PAIS+DT_VENC+EMISSOR: excess=0 em 202301 (52,154),
          # 202311 (81,459), 202312, 202401, 202603, 202604 e 202605.
          # Sweep 202301-202311 (servidor, 2026-09) confirma excess=0 em todos
          # os meses — unicidade intacta.
          # NULL-rate (gate 1%, probe estendido): DS_ATIVO_EXTERIOR vazio em
          # 8,503/52,154 (16,3% em 202301) a 3,908/53,847 (7,26% em 202605) —
          # descritor em texto livre do ativo no exterior, em branco quando a
          # posicao ja e identificada pelo codigo do mercado de balcao
          # (CD_ATIVO_BV_MERC) + nome do emissor (EMISSOR); padrao em fundos
          # offshore, DRs, opcoes, acoes e bonds. DT_VENC vazio em 4,531/52,154
          # (8,7% em 202301) a 1,798/53,847 (3,3% em 202605) — ativos sem
          # vencimento fixo: cotas de fundos offshore, DRs e acoes nao tem data
          # de vencimento. EMISSOR vazio em 823/64,096 (1,28% em 202303,
          # unico mes acima do gate de 1%; demais meses 419-546/52k-81k,
          # 0,6-0,9%) — posicoes sem emissor nomeado no arquivo; whitelisted
          # pelo breach medido, mesmo tratamento das eras HIST (que ja
          # whitelistan emissor). Unicidade permanece 0 com as colunas na
          # chave.
        - nome: blc_8
          arquivo: "cda_fi_BLC_8_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, ds_ativo, tp_negoc]
          chaves_permitem_nulos: [cpf_cnpj_emissor]
          # VERIFICADA: chave 7-colunas sem tp_negoc tinha excess=1 (202301
          # e 202311, TP_NEGOC variando); com tp_negoc, excess=0 em ambas.
          # NULL-rate (gate 1%, probe estendido): CPF_CNPJ_EMISSOR vazio em
          # 147,539/183,523 (80,4% em 202301) a 84,320/199,926 (42,2% em
          # 202605) — identificador fiscal brasileiro do emissor; vazio quando
          # o emissor nao e pessoa fisica/juridica brasileira identificavel
          # por CPF/CNPJ: posicoes operacionais sem emissor (Disponibilidades,
          # Valores a Receber/Pagar), derivativos/opcoes negociados em bolsa
          # (futuros e opcoes nao tem emissor-CNPJ) e emissores offshore (BDR
          # nao patrocinado). DS_ATIVO/EMISSOR carregam o rotulo; unicidade
          # permanece 0 com a coluna na chave.
        - nome: pl
          arquivo: "cda_fi_PL_{aaaamm}.csv"
          chave: [tp_fundo, cnpj_fundo, dt_comptc]
          # VERIFICADA: excess=0 em 202301 (24,937) e 202311 — um PL por fundo
          # por data, como construcao.
    - nome: corrente_2024
      url: https://dados.cvm.gov.br/dados/FI/DOC/CDA/DADOS/cda_fi_{aaaamm}.zip
      vigencia: { de: "202312", ate: "202401" }
      layout: zip_multi_tabela
      tabelas:
        - nome: fiim
          arquivo: "cda_fiim_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor, tp_negoc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor]
          # TOLERADA_COM_RESIDUO (re-medido 2026-08, zips reais 202312/202401):
          # excess=2 em 202312 (4,622) e 2 em 202401 (4,712); 0 grupos
          # exatos, 2 grupos residuais nao-exatos em cada. Mesma decisao de
          # dominio da era corrente_2023 (ver la o raciocinio completo e o
          # exemplo com verificacao de VL_PATRIM_LIQ): FIIM/FIE e posicao por
          # LOTE, residuo e a regra (lotes com agio/deságio proprio, valor
          # diferente), nao excecao. excess_excl_null_keys=0: residuo so
          # onde a propria chave e NULL — estrutural (ativo sem codigo
          # publico), nao confidencialidade temporaria (essa ja e coberta
          # por fie_confid/confid). Whitelisted com % medido: tp_ativo
          # 3,5-3,7%, cd_ativo ~13%, ds_ativo ~90%, dt_venc ~91%,
          # cpf_cnpj_emissor ~94%, emissor ~87%. Cap excesso exato 20
          # (medido 0). Cap grupos residuais 10 (~5x o maximo desta era, 2).
        - nome: blc_1
          arquivo: "cda_fi_BLC_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_isin, dt_venc, tp_negoc]
          # VERIFICADA: chave 7-colunas sem tp_negoc tinha excess=157 (202312)
          # e 147 (202401), TP_NEGOC variando em 100% dos grupos. Com
          # tp_negoc: excess=0 em 202312 (43,486) e 202401 (44,023).
        - nome: blc_2
          arquivo: "cda_fi_BLC_2_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cnpj_fundo_classe_cota, id_subclasse]
          chaves_permitem_nulos: [id_subclasse]
          # VERIFICADA: probe excess=0 em 202312 e 202401 (medido agora; a
          # parte inteira foi re-medida contra os zips baixados). id_subclasse
          # 100% NULL nesta era (183.805/183.805 em 202312, 181.133/181.133 em
          # 202401) - sem o whitelist, promoveria "verificada" mas falharia o
          # null-rate gate no primeiro run real, mesmo bug do blc_7/blc_8 que
          # ja mordeu este projeto. Mesmo padrao ja whitelisted na era
          # corrente_202402/corrente_202605 (abaixo) - esta entrada tinha
          # ficado para tras.
        - nome: blc_3
          arquivo: "cda_fi_BLC_3_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_swap]
          # VERIFICADA: probe excess=0 em 202312 e 202401.
        - nome: blc_4
          arquivo: "cda_fi_BLC_4_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo, cd_isin, tp_negoc]
          # VERIFICADA: com tp_negoc, excess=0 em 202312 (198,205) e 202401
          # (204,469). Chave 7-colunas sem tp_negoc dava 0 aqui tambem (so
          # 202301 na era TP_FUNDO precisou do fix); mantido tp_negoc por
          # consistencia com a parte corrente_post.
        - nome: blc_5
          arquivo: "cda_fi_BLC_5_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # VERIFICADA: chave-perfil de remuneracao (ver corrente_2023). Probe
          # excess=0 em 202312 (65,018) e 202401 (67,721). Colunas de taxa em
          # chaves_permitem_nulos (PR_TAXA_PREFX ~96% NULL em 202312).
        - nome: blc_6
          arquivo: "cda_fi_BLC_6_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx, titulo_cetip, titulo_garantia, tp_negoc]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # VERIFICADA: chave-perfil + cetip/garantia/tp_negoc (ver
          # corrente_2023). Probe excess=0 em 202312 (11,486) e 202401 (9,793).
        - nome: blc_7
          arquivo: "cda_fi_BLC_7_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo_bv_merc, ds_ativo_exterior, cd_bv_merc, cd_pais, dt_venc, emissor]
          chaves_permitem_nulos: [ds_ativo_exterior, dt_venc]
          # VERIFICADA: chave completa com CD_BV_MERC+CD_PAIS+DT_VENC+EMISSOR:
          # excess=0 em 202312 (75,281) e 202401 (79,919). Chave antiga tinha
          # excess ~1,800.
          # NULL-rate (gate 1%, probe estendido): DS_ATIVO_EXTERIOR vazio em
          # 8,054/75,281 (10,7% em 202312) e 8,094/79,919 (10,1% em 202401) e
          # DT_VENC vazio em 4,718/75,281 (6,3%) e 4,773/79,919 (6,0%) —
          # descritor em texto livre em branco quando a posicao ja e
          # identificada pelo codigo+emissor; vencimento ausente em ativos sem
          # vencimento fixo (fundos offshore, DRs, acoes). Unicidade segue 0.
        - nome: blc_8
          arquivo: "cda_fi_BLC_8_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, ds_ativo, tp_negoc]
          chaves_permitem_nulos: [cpf_cnpj_emissor]
          # VERIFICADA: chave 7-colunas sem tp_negoc tinha excess=1 (202312 e
          # 202401, TP_NEGOC variando); com tp_negoc, excess=0 em ambas.
          # NULL-rate (gate 1%, probe estendido): CPF_CNPJ_EMISSOR vazio em
          # 120,073/194,392 (61,8% em 202312) e 119,052/194,407 (61,2% em
          # 202401) — identificador fiscal brasileiro do emissor, vazio quando
          # o emissor nao e identificavel por CPF/CNPJ (posicoes operacionais
          # sem emissor, derivativos/opcoes de bolsa, emissores offshore).
        - nome: pl
          arquivo: "cda_fi_PL_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          # VERIFICADA: probe excess=0 em 202312 e 202401 — um valor de PL por
          # fundo por data, confirmado por construcao.
    - nome: corrente_202402
      url: https://dados.cvm.gov.br/dados/FI/DOC/CDA/DADOS/cda_fi_{aaaamm}.zip
      # Vigencia termina em 202604. O arquivo cda_fie_CONFID apareceu nas
      # copias de 202605 baixadas 2026-08-14/18/25, mas a CVM o retirou na
      # republicacao mais recente (2026-09-06,
      # sha256=97c471c4b848115178dfdd173c24df2a28d7af5a525639499f9840e58f4c495c).
      # Bronze usa sempre a ultima versao raw; fie_confid so passa a valer em
      # 202606, onde o membro existe e a chave foi medida. Ver abaixo.
      vigencia: { de: "202402", ate: "202604" }
      layout: zip_multi_tabela
      tabelas:
        - nome: fiim
          arquivo: "cda_fie_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor, tp_negoc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 350
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor, tp_negoc]
          # TOLERADA_COM_RESIDUO (re-medido 2026-08, zips reais): excess=406
          # em 202603 (22,150) e 229 em 202604 (18,278); 0 grupos exatos, 238
          # e 114 grupos residuais nao-exatos. Mesma decisao de dominio da
          # era corrente_2023 (ver la o exemplo com VL_PATRIM_LIQ): FIIM/FIE
          # e posicao por LOTE, residuo e a regra. excess_excl_null_keys=0:
          # residuo so onde a propria chave tem NULL (FIAGRO CPR com
          # identificadores NULL diferindo so em VL_MERC_POS_FINAL; ativos
          # externos tipo IT NOW RUSSELL com cd_ativo=1, distinguiveis so
          # por emissor/QT_POS_FINAL) — estrutural, nao confidencialidade
          # temporaria (essa e coberta por fie_confid/confid, separadas).
          # Whitelisted com % medido: tp_ativo 35-41%, cd_ativo 72-75%,
          # ds_ativo 68-71%, dt_venc 89-93%, cpf_cnpj_emissor 53-55%,
          # emissor 52-53%, tp_negoc 32-36% (esta ultima so aparece nesta
          # era e na corrente_202605). Cap excesso exato 20 (medido 0). Cap
          # grupos residuais 350 (~1,5x o maximo desta era, 238 — a mais
          # ativa medida; ajustar se o backfill historico revelar volume
          # maior).
        - nome: blc_1
          arquivo: "cda_fi_BLC_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_isin, dt_venc, tp_negoc]
          # VERIFICADA: chave anterior (sem tp_negoc) tinha excess=215/205
          # (202603/202604), TP_NEGOC variando em 100% dos grupos duplicados.
          # Com tp_negoc adicionado: excess_rows=0 em 202603/202604/202605.
        - nome: blc_2
          arquivo: "cda_fi_BLC_2_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cnpj_fundo_classe_cota, id_subclasse]
          chaves_permitem_nulos: [id_subclasse]
          # VERIFICADA: excess=0 em 202603/202604/202605. id_subclasse ~100%
          # NULL (128,299/128,328) - whitelisted no gate de null-rate.
        - nome: blc_3
          arquivo: "cda_fi_BLC_3_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_swap]
          # VERIFICADA: excess=0 em 202603/202604/202605.
        - nome: blc_4
          arquivo: "cda_fi_BLC_4_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo, cd_isin, tp_negoc]
          # VERIFICADA: chave anterior (sem tp_negoc) tinha excess=3/3/2,
          # TP_NEGOC variando em todos os grupos. Com tp_negoc: excess=0 em
          # 202603/202604/202605.
        - nome: blc_5
          arquivo: "cda_fi_BLC_5_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep 202402-202604 + extensao 202501-202512
          # e 202601-202607, downloads atuais de 2026-09): maximo=6 grupos
          # residuais em 202406 (6 excess, 0 exatos); 202410 mediu 5, 202409
          # 4; 202601-202607 fecharam em 0. Nenhum grupo e byte-identico em
          # nenhum mes — os residuais variam TP_NEGOC/QT_POS_FINAL/
          # VL_MERC_POS_FINAL (mais QT/VL_AQUIS/VENDA_NEGOC): mesma posicao
          # com splits de negociacao distintos, contradicao da fonte. A chave
          # HIST com +tp_negoc continua tolerada_com_residuo 20/10 — tp_negoc
          # nao fecha. Caps 5/10. Estabilidade 202603→202604 (lotes estaveis)
          # continua valendo para os grupos exatos, que seguem em 0.
        - nome: blc_6
          arquivo: "cda_fi_BLC_6_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx, titulo_cetip, titulo_garantia, tp_negoc]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep 202402-202512, 23 zips no servidor,
          # downloads atuais de 2026-09): maximo=5 grupos residuais em 202410
          # (5 excess, 0 exatos); 202407-202409 mediram 3, 202405-202406 2;
          # demais meses fecharam em 0. Nenhum grupo e byte-identico —
          # residuais variam somente QT_POS_FINAL/VL_MERC_POS_FINAL: mesma
          # posicao com quantidade/valor distintos, contradicao da fonte.
          # Era VERIFICADA por extrapolacao (0 em 202603/202604/202605).
          # Caps 5/10. NULL-rate limpo em todos os meses.
        - nome: blc_7
          arquivo: "cda_fi_BLC_7_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo_bv_merc, ds_ativo_exterior, cd_bv_merc, cd_pais, dt_venc, emissor]
          chaves_permitem_nulos: [ds_ativo_exterior, dt_venc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep 202402-202604 + extensao 202501-202512
          # e 202601-202607, downloads atuais de 2026-09): maximo=2 grupos
          # residuais em 202504-202509 (2 excess, 0 exatos); 202412-202503 e
          # 202510-202512 mediram 1; 202601-202607 fecharam em 0. Nenhum grupo
          # e byte-identico — residuais variam TP_NEGOC/QT_POS_FINAL/
          # VL_MERC_POS_FINAL: mesma posicao com split de negociacao distinto,
          # contradicao da fonte. Era VERIFICADA por extrapolacao (0 em
          # 202603/202604/202605). Caps 5/5. NULL-rate limpo (emissor ~0,1%).
          # NULL-rate (gate 1%, probe estendido): DS_ATIVO_EXTERIOR vazio em
          # 6,928/56,777 (12,2% em 202603), 6,629/58,284 (11,4% em 202604) e
          # 3,908/53,847 (7,3% em 202605); DT_VENC vazio em 4,268/56,777
          # (7,5%), 4,053/58,284 (7,0%) e 1,798/53,847 (3,3%) — descritor em
          # texto livre em branco quando a posicao ja e identificada por
          # codigo+emissor; vencimento ausente em ativos sem vencimento fixo.
        - nome: blc_8
          arquivo: "cda_fi_BLC_8_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, ds_ativo, tp_negoc]
          chaves_permitem_nulos: [cpf_cnpj_emissor]
          # VERIFICADA: chave anterior (sem tp_negoc) tinha excess=2/0/0.
          # Com tp_negoc: excess=0 em 202603/202604/202605.
          # NULL-rate (gate 1%, probe estendido): CPF_CNPJ_EMISSOR vazio em
          # 126,971/253,088 (50,2% em 202603), 124,098/243,846 (50,9% em
          # 202604) e 84,320/199,926 (42,2% em 202605) — identificador fiscal
          # brasileiro do emissor, vazio quando o emissor nao e identificavel
          # por CPF/CNPJ (posicoes operacionais, derivativos de bolsa,
          # emissores offshore).
        - nome: pl
          arquivo: "cda_fi_PL_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          # VERIFICADA: excess=0 em 202603/202604/202605.
        - nome: confid
          arquivo: "cda_fi_CONFID_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic]
          vigencia: { de: "202603" }
          # VERIFICADA: probe excess=0 em 202603 (8,880), 202604 (8,487) e
          # 202605 (56,477). era pendente (arquivo omitido do catalogo);
          # medido agora.
    - nome: corrente_202605
      url: https://dados.cvm.gov.br/dados/FI/DOC/CDA/DADOS/cda_fi_{aaaamm}.zip
      vigencia: { de: "202605", ate: null }
      layout: zip_multi_tabela
      tabelas:
        - nome: fiim
          arquivo: "cda_fie_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor, tp_negoc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 20
          max_grupos_residuais: 250
          politica_dedup_silver: keep_first
          chaves_permitem_nulos: [tp_ativo, cd_ativo, ds_ativo, dt_venc, cpf_cnpj_emissor, emissor, tp_negoc]
          # TOLERADA_COM_RESIDUO (sweep 202605-202607, todos os meses locais):
          # maximo em 202606 = 18.503 linhas, 292 excess totais, 1 excess
          # exato e 210 grupos residuais nao-exatos; 202605=78/64 e
          # 202607=50/45 (excess/grupos residuais). Caps 20/250. Mesma
          # decisao de dominio da era corrente_2023: FIIM/FIE e posicao por LOTE;
          # residuo e a regra. excess_excl_null_keys=0: residual so onde a
          # propria chave tem NULL (FIAGRO CPR com colunas NULL diferindo so
          # em valor; ativos externos distinguiveis apenas por
          # emissor/QT_POS_FINAL) — estrutural, nao confidencialidade
          # temporaria (coberta por fie_confid/confid, separadas).
          # Whitelisted com % medido na versao anterior: tp_ativo 40%,
          # cd_ativo 67%, ds_ativo 72%, dt_venc 94%, cpf_cnpj_emissor 53%,
          # emissor 51%, tp_negoc 35%. Cap excesso exato 20 (medido 0). Cap
          # residual 185 (~1,5x o maximo mais recente, 122).
        - nome: blc_1
          arquivo: "cda_fi_BLC_1_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_isin, dt_venc, tp_negoc]
          # VERIFICADA: com tp_negoc, excess=0 em 202603/202604/202605.
        - nome: blc_2
          arquivo: "cda_fi_BLC_2_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cnpj_fundo_classe_cota, id_subclasse]
          chaves_permitem_nulos: [id_subclasse]
          # VERIFICADA: excess=0 em 202603/202604/202605. id_subclasse ~100%
          # NULL - whitelisted.
        - nome: blc_3
          arquivo: "cda_fi_BLC_3_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_swap]
          # VERIFICADA: excess=0.
        - nome: blc_4
          arquivo: "cda_fi_BLC_4_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo, cd_isin, tp_negoc]
          # VERIFICADA: com tp_negoc, excess=0 em 202603/202604/202605.
        - nome: blc_5
          arquivo: "cda_fi_BLC_5_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # VERIFICADA: chave-perfil de remuneracao (ver corrente_2023). Probe
          # excess=0 em 202605 (36,687).
        - nome: blc_6
          arquivo: "cda_fi_BLC_6_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, dt_venc, pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx, titulo_cetip, titulo_garantia, tp_negoc]
          chaves_permitem_nulos: [pr_cupom_posfx, pr_taxa_prefx, pr_indexador_posfx, cd_indexador_posfx]
          # VERIFICADA: chave-perfil + cetip/garantia/tp_negoc. Probe excess=0
          # em 202605 (2,257).
        - nome: blc_7
          arquivo: "cda_fi_BLC_7_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cd_ativo_bv_merc, ds_ativo_exterior, cd_bv_merc, cd_pais, dt_venc, emissor]
          chaves_permitem_nulos: [ds_ativo_exterior, dt_venc]
          # VERIFICADA: mesma chave resolveu 202603/202604/202605 — excess=0
          # em 202605 (53,847). Chave antiga tinha excess ~1.4k.
          # NULL-rate (gate 1%, probe estendido): DS_ATIVO_EXTERIOR vazio em
          # 3,908/53,847 (7,26% em 202605) e DT_VENC vazio em 1,798/53,847
          # (3,34%) — descritor em texto livre em branco quando a posicao ja
          # e identificada por codigo+emissor; vencimento ausente em ativos
          # sem vencimento fixo (fundos offshore, DRs, acoes).
        - nome: blc_8
          arquivo: "cda_fi_BLC_8_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, tp_ativo, cpf_cnpj_emissor, ds_ativo, tp_negoc]
          chaves_permitem_nulos: [cpf_cnpj_emissor]
          # VERIFICADA: com tp_negoc, excess=0 em 202603/202604/202605.
          # NULL-rate (gate 1%, probe estendido): CPF_CNPJ_EMISSOR vazio em
          # 84,320/199,926 (42,2% em 202605) — identificador fiscal brasileiro
          # do emissor, vazio quando o emissor nao e identificavel por
          # CPF/CNPJ (posicoes operacionais, derivativos de bolsa, emissores
          # offshore).
        - nome: pl
          arquivo: "cda_fi_PL_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc]
          # VERIFICADA: excess=0.
        - nome: confid
          arquivo: "cda_fi_CONFID_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic]
          # VERIFICADA: probe excess=0 em 202605 (56,477 linhas). era pendente;
          # medido agora.
        - nome: fie_confid
          arquivo: "cda_fie_CONFID_{aaaamm}.csv"
          chave: [tp_fundo_classe, cnpj_fundo_classe, dt_comptc, tp_aplic, id_doc]
          vigencia: { de: "202606" }
          # VERIFICADA: a CVM retirou o membro da ultima versao de 202605
          # (historicamente ele existiu, mas bronze le o raw mais recente).
          # Em 202606: 802 linhas, excess=0 e 0% NULL em toda a chave. A
          # chave [BASE, id_doc] historica tinha excess=430 porque TP_APLIC
          # variava em 100% dos 158 grupos; com tp_aplic, excess=0.

# ────────────────────────────────────────────────────────────
# cia_aberta_dfp / cia_aberta_itr — shape C (zip multi-tabela), grao anual
#
# VERIFICADO empiricamente nesta sessao contra dfp_cia_aberta_2024/2025.zip
# e itr_cia_aberta_2024/2025.zip: um unico zip por ANO (nunca por mes/
# trimestre, mesmo para o ITR que e trimestral em conteudo — DT_REFER
# dentro do arquivo varia por trimestre, mas o pacote e sempre anual).
# Isso e a correcao do ticket C: grao_competencia: ano evita baixar o
# mesmo zip 12x por ano. 19 arquivos por zip, schemas genuinamente
# distintos (balanco patrimonial, DRE, fluxo de caixa, etc, cada um em
# versao consolidada "con" e individual "ind").
#
# MEDIDO nesta sessao (probe, competencias 2024 e 2025):
#   * A chave [cnpj_cia, dt_refer, versao, cd_conta, ordem_exerc] falha em
#     quase todas as tabelas de demonstracoes por DUAS razoes distintas:
#       1. DRE/DRA do ITR: falta uma dimensao real de PERIODO. Dentro de um
#          mesmo cnpj+dt_refer+versao+cd_conta+ordem_exerc a CVM publica uma
#          linha por DT_INI_EXERC (1T/2T/3T do ano e o comparativo do ano
#          anterior) — 62.656/90.403 excess (2025) e 66.750/96.378 (2024).
#          A chave dessas 4 tabelas ganhou dt_ini_exerc e fecha.
#       2. DMPL (con/ind de DFP e ITR): falta a dimensao COLUNA_DF
#          (patrimonio liquido tem coluna por exercicio). Medido de
#          197.764->1.424 (dfp con 2025) e de 546.201->912 (itr con 2025).
#          A chave dessas 4 tabelas ganhou coluna_df.
#       3. Residuo apos a correcao: linhas byte-identicas que a propria CVM
#          publica 2-3x para algumas companhias — vira chave_status
#          "tolerada" com cap absoluto e politica de dedup no silver. As
#          tabelas com algum grupo NAO byte-identico (DS_CONTA ou VL_CONTA
#          variando no mesmo cd_conta) ficam "pendente" com a evidencia.
#   * "origem"/"grupo_dfp" NAO existem nos arquivos brutos da CVM;
#     "grupo_dfp" e um seletor de tabela, nao uma coluna dentro dela.
#   * Base do DFP 2024 tem 1 linha nao-exata (ID_DOC/DT_RECEB/LINK_DOC
#     variam — documento reenviado), 2025 = 0. A antiga observacao de 2023
#     (1 em 893) foi da mesma familia.
# ────────────────────────────────────────────────────────────
- id: cia_aberta_dfp
  fonte: cvm
  dominio: cia_aberta
  periodicidade: anual
  grao_competencia: ano
  encoding: cp1252
  sep: ";"
  snapshot: false
  restatement: true
  partes:
    - nome: unica
      url: https://dados.cvm.gov.br/dados/CIA_ABERTA/DOC/DFP/DADOS/dfp_cia_aberta_{aaaa}.zip
      layout: zip_multi_tabela
      tabelas:
        - nome: base
          arquivo: "dfp_cia_aberta_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, dt_receb]
          chave_status: verificada
          # VERIFICADA (medido 2024/2025 com V3: dt_receb+versao): 2024 = 0
          # excess em 873 linhas; 2025 = 0. Chave fecha em 0 com dt_receb+
          # versao. A coluna dt_receb marca re-entrega de documento (isolador
          # de metadata-only de TRAVESSIA e outras re-submissões).
        - nome: bpa_con
          arquivo: "dfp_cia_aberta_BPA_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 2000
          politica_dedup_silver: keep_first
          # TOLERADA (sweep completo 2010-2026, 17 zips locais): maximo=1.649
          # excess em 2023, todos os 1.393 grupos byte-identicos. 2022=898,
          # 2024=256, 2025=446; demais <=2. Cap 2.000.
        - nome: bpa_ind
          arquivo: "dfp_cia_aberta_BPA_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 4000
          max_grupos_residuais: 50
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep completo 2010-2026, 17 zips locais):
          # maximos em 2023 = 3.271 excess totais, 3.235 excess exatos e 36
          # grupos residuais, variando somente VL_CONTA. 2022=1.830 excess,
          # todos exatos; 2024=730 e 2025=440. Caps 4.000/50. A divergencia de
          # valor de 2023 impede classificar a parte inteira como tolerada.
        - nome: bpp_con
          arquivo: "dfp_cia_aberta_BPP_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 3500
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zips atuais 2022/2023
          # no servidor): 2022 = 1.500 excess (1.278 exatos + 2 residuais
          # VL_CONTA); 2023 = 2.855 (2.395 + 4). Residual = valor contradito
          # pela fonte. Caps 3.500/10.
          # TOLERADA (medido 2024/2025): 2024 = 456 excess (200/200 exatos);
          # 2025 = 736 excess (312/312 exatos). Mesma publicacao repetida da
          # CVM. Cap 1.000 = ~1,4x o maximo medido (736). dt_ini_exerc no fecha.
        - nome: bpp_ind
          arquivo: "dfp_cia_aberta_BPP_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 6500
          max_grupos_residuais: 40
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zips atuais 2022/2023
          # no servidor): 2022 = 3.218 excess (2.365 exatos + 3 residuais
          # VL_CONTA); 2023 = 5.665 (3.970 + 29). Caps 6.500/40 (era 2.000/5,
          # medido em 2024/2025 — restatement estourou).
          # TOLERADA_COM_RESIDUO (re-medido com probe_dataset direto, chave final):
          # 2024 = 159.522 linhas, excess exato=1.306 (986 grupos exatos), 2 grupos
          # RESIDUAIS (VL_CONTA diverge no mesmo cnpj_cia+dt_refer+versao+cd_conta+
          # ds_conta+ordem_exerc — a CVM publicou valores contraditos, ver
          # _residuos.json); 2025 = 736 excess exato, 0 residuais. ds_conta ja
          # resolveu as divergencias de rotulo (100% dos grupos com divergencia
          # de rotulo tem ST_CONTA_FIXA='N'); os 2 grupos residuais sao valor, nao
          # rotulo — nenhuma chave resolve. Cap excesso exato 2.000 (~1,5x o maximo
          # medido, 1.306); cap grupos residuais 5 (2024 mediu 2). Cada grupo
          # residual e escrito em _residuos.json ao lado da particao promovida —
          # ver ARCHITECTURE.md Sec 6.12 (chave_status contract).
        - nome: composicao_capital
          arquivo: "dfp_cia_aberta_composicao_capital_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao]
          vigencia: { de: "2020" }
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (sweep completo da vigencia 2020-2026, 7 zips locais):
          # 2021 e 2023 mediram 1 excess cada, grupos byte-identicos; demais 0.
          # Cap 5.
        - nome: dfc_md_con
          arquivo: "dfp_cia_aberta_DFC_MD_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 200
          politica_dedup_silver: keep_first
          # TOLERADA (sweep completo 2010-2026, 17 zips locais): maximo=144
          # excess em 2022 (72 grupos de tamanho 3, todos byte-identicos);
          # 2023=98 exatos, demais competencias tiveram 0 excess. Cap 200.
          # O zip local 2026 contem 0 linhas nesta tabela, logo nao reproduz
          # o erro do re-run remoto citado na triagem.
        - nome: dfc_md_ind
          arquivo: "dfp_cia_aberta_DFC_MD_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 350
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zips atuais 2021/2022/2023 no
          # servidor): 2021 = 28 excess (14 grupos, todos exatos); 2022 = 212
          # (138 exatos); 2023 = 282 (212 exatos). 100% republicacao. Cap 350.
          # VERIFICADA (medido 2024/2025 com +ds_conta): 0 excess nas duas
          # competencias (ds_conta nao muda o resultado: tabela ja fechava).
        - nome: dfc_mi_con
          arquivo: "dfp_cia_aberta_DFC_MI_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 1500
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 2023 no servidor):
          # 2023 = 1.098 excess (872 grupos, 100% exatos). Cap 500 (medido
          # 2024/2025) estourado pelo restatement; novo cap 1.500.
          # TOLERADA (medido 2024/2025 com +ds_conta): 2024 = 230 excess,
          # 100% exatos; 2025 = 320 excess, 100% exatos. ds_conta nao
          # dissolve esses grupos. Cap 500 = ~1,6x o maximo medido.
        - nome: dfc_mi_ind
          arquivo: "dfp_cia_aberta_DFC_MI_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 1500
          max_grupos_residuais: 50
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zips atuais 2022/2023
          # no servidor): 2022 = 920 excess (731 exatos + 11 residuais
          # VL_CONTA); 2023 = 1.320 (984 + 40 grupos com DT_INI_EXERC
          # distinto — mesma conta, inicio de exercicio corrigido; E3 do
          # artefato bucket-c mostra o par). Caps 1.500/50 (era 750/6).
          # TOLERADA_COM_RESIDUO (re-medido com probe_dataset direto, chave final):
          # 2024 = 68.557 linhas, excess exato=509 (412 grupos exatos), 3 grupos
          # RESIDUAIS (VL_CONTA diverge no mesmo cnpj_cia+dt_refer+versao+cd_conta+
          # ds_conta+ordem_exerc — valores contraditos pela CVM, ver
          # _residuos.json); 2025 = 332 excess exato, 0 residuais. Cap excesso
          # exato 750 (~1,5x o maximo medido, 509); cap grupos residuais 6 (2024
          # mediu 3). Ver ARCHITECTURE.md Sec 6.12 (chave_status contract).
        - nome: dmpl_con
          arquivo: "dfp_cia_aberta_DMPL_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc, coluna_df]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 7000
          max_grupos_residuais: 80
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zips atuais 2022/2023
          # no servidor): 2022 = 3.200 excess (2.728 grupos, 100% exatos);
          # 2023 = 6.176 (5.133 exatos + 67 residuais VL_CONTA). Status saiu
          # de tolerada: 2023 tem residuo. Caps 7.000/80.
          # TOLERADA (medido 2024/2025 com +ds_conta): 2024 = 1.032 excess,
          # excess_excl_null_keys=1.032 (100% byte-idênticos); 2025 = 1.424 excess,
          # excess_excl_null_keys=1.424 (100% byte-idênticos). ds_conta resolve
          # divergências de rótulo — validado: 100% dos grupos com rótulo divergente
          # têm ST_CONTA_FIXA='N' (conta definida pela empresa, não do plano padrão
          # CVM). Cap 2.000 = ~1,4x o maximo medido.
        - nome: dmpl_ind
          arquivo: "dfp_cia_aberta_DMPL_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc, coluna_df]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10000
          max_grupos_residuais: 500
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zip 2023 no
          # servidor — numeros do GATE, autoritativos para o cap exato:
          # 8.538 linhas excedentes exatas em 2023; grupos residuais
          # distintos = 6.360 - 5.977 = 383 (probe conta grupos, gate conta
          # linhas — ver licao groups-vs-rows no artefato bucket-c). O cap
          # 7.000/350 anterior usou grupos no lugar de linhas. Caps
          # 10.000/500.
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zips atuais 2022/2023
          # no servidor): 2022 = 5.016 excess (3.644 exatos + 16 residuais
          # VL_CONTA); 2023 = 8.970 (5.977 + 312 grupos com DT_INI_EXERC
          # distinto + 71 VL_CONTA). Cap residual 350: os pares DT_INI_EXERC
          # medidos carregam o mesmo VL_CONTA (correcao de metadado, E3 do
          # artefato bucket-c) — cap, nao re-chave. Status saiu de tolerada.
          # Caps 7.000/350.
          # TOLERADA (medido 2024/2025 com +ds_conta): 2024 = 2.052 excess,
          # excess_excl_null_keys=2.052 (100% byte-idênticos); 2025 = 1.068 excess,
          # excess_excl_null_keys=1.068 (100% byte-idênticos). ds_conta resolve
          # divergências de rótulo — validado: 100% dos grupos com rótulo divergente
          # têm ST_CONTA_FIXA='N' (conta definida pela empresa). Cap 2.500.
        - nome: dra_con
          arquivo: "dfp_cia_aberta_DRA_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 200
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08 noite, zip atual 2023 no servidor):
          # 2023 = 151 excess (131 grupos, 100% exatos — gate confirma 151
          # linhas exatas). Cap 100 -> 200.
          # TOLERADA (medido 2024/2025): 2024 = 22 excess, 100% exatos;
          # 2025 = 30 excess, 100% exatos. Cap 100 = ~3,3x o maximo medido.
          # dt_ini_exerc no fecha.
        - nome: dra_ind
          arquivo: "dfp_cia_aberta_DRA_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 250
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zip atual 2023
          # no servidor): 2023 = ~179 exatas + 6 residuais DT_INI_EXERC (185
          # excess, 137 grupos). Era tolerada 100. Caps 250/10.
          # TOLERADA (medido 2024/2025): 2024 = 38 excess, 100% exatos;
          # 2025 = 18 excess, 100% exatos. Cap 100 = ~2,6x o maximo medido.
          # dt_ini_exerc no fecha.
        - nome: dre_con
          arquivo: "dfp_cia_aberta_DRE_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 1000
          max_grupos_residuais: 25
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zip atual 2023
          # no servidor): 2023 = ~825 exatas + 18 residuais VL_CONTA (845
          # excess, 721 grupos). Era tolerada 500. Caps 1.000/25.
          # TOLERADA (medido 2024/2025): 2024 = 128 excess, 100% exatos;
          # 2025 = 210 excess, 100% exatos. Cap 500 = ~2,4x o maximo medido.
          # dt_ini_exerc no fecha (DRE/DFP: ano fechado, coluna_DF nao existe).
          # Fecha a investigacao da discrepancia de 702.608 linhas de
          # ARCHITECTURE.md Sec 3 — sao duplicatas byte-identicas de CVM +
          # (no ITR) o grao de periodo dt_ini_exerc ausente (ver itr/dre).
        - nome: dre_ind
          arquivo: "dfp_cia_aberta_DRE_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 1600
          max_grupos_residuais: 85
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zips atuais no
          # servidor): 2022 = ~864 exatas + 4 residuais VL_CONTA (868 excess,
          # 638 grupos); 2023 = ~1.439 + 71 residuais (DT_INI_EXERC em 56,
          # VL_CONTA em 15; 1.510 excess, 1.086 grupos). Era tolerada 500 —
          # escondida atras de sumario truncado em rounds anteriores. Caps
          # 1.600/85.
          # TOLERADA (medido 2024/2025): 2024 = 338 excess, 100% exatos;
          # 2025 = 202 excess, 100% exatos. Cap 500 = ~1,5x o maximo medido.
          # dt_ini_exerc no fecha.
        - nome: dva_con
          arquivo: "dfp_cia_aberta_DVA_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 1300
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zips atuais no
          # servidor): 2022 = 576 exatas + 0 residuais (496 grupos); 2023 =
          # ~1.085 + 4 residuais VL_CONTA (1.090 excess, 922 grupos). Era
          # tolerada 500. Caps 1.300/10.
          # TOLERADA (medido 2024/2025): 2024 = 196 excess, 100% exatos;
          # 2025 = 252 excess, 100% exatos. Cap 500 = ~2x o maximo medido.
          # dt_ini_exerc no fecha.
        - nome: dva_ind
          arquivo: "dfp_cia_aberta_DVA_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 2500
          max_grupos_residuais: 110
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zips atuais no
          # servidor): 2022 = 1.198 exatas + 0 residuais (882 grupos);
          # 2023 = ~2.100 + 95 residuais (DT_INI_EXERC em 78, VL_CONTA em 17;
          # 2.213 excess, 1.561 grupos). Caps 2.500/110 (era 800/15).
          # TOLERADA_COM_RESIDUO (re-medido com probe_dataset direto, chave final):
          # 2024 = 59.742 linhas, excess exato=517 (395 grupos exatos), 9 grupos
          # RESIDUAIS (VL_CONTA diverge no mesmo cnpj_cia+dt_refer+versao+cd_conta+
          # ds_conta+ordem_exerc — a CVM publicou valores contraditos, um exemplo
          # medido: cd_conta 7.01.01 "Vendas de Mercadorias" 0 vs 121.672 — ordem
          # de grandeza, nao arredondamento; ver _residuos.json); 2025 = 238 excess
          # exato, 0 residuais. Cap excesso exato 800 (~1,5x o maximo medido, 517);
          # cap grupos residuais 15 (2024 mediu 9). Ver ARCHITECTURE.md Sec 6.12 (chave_status contract).
        - nome: parecer
          arquivo: "dfp_cia_aberta_parecer_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, tp_relat_aud, tp_parecer_decl, num_item_parecer_decl]
          chaves_permitem_nulos: [tp_relat_aud]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zip atual 2021 no
          # servidor): 2021 = 7 excess (0 exatos, 7 residuais variando
          # TXT_PARECER_DECL — declaracoes re-assinadas, E4 do artefato
          # bucket-c). Era verificada por extrapolacao. Caps 5/10.
          # VERIFICADO: +tp_parecer_decl fecha em 0 excedentes (2024 e 2025).
          # A chave anterior media 1.256 excedentes em 3.715 (2025) apenas por
          # colapso de NULL: TP_RELAT_AUD e nulo em 2.048 das 3.715 linhas e o
          # DISTINCT do DuckDB junta todos os NULLs num grupo so —
          # excess_excl_null_keys ja era 0. TP_PARECER_DECL variava em 100% dos
          # grupos (um parecer tem varias declaracoes por relatorio).

- id: cia_aberta_itr
  fonte: cvm
  dominio: cia_aberta
  periodicidade: anual
  grao_competencia: ano
  encoding: cp1252
  sep: ";"
  snapshot: false
  restatement: true
  partes:
    - nome: unica
      url: https://dados.cvm.gov.br/dados/CIA_ABERTA/DOC/ITR/DADOS/itr_cia_aberta_{aaaa}.zip
      layout: zip_multi_tabela
      tabelas:
        - nome: base
          arquivo: "itr_cia_aberta_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, dt_receb]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 5
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep completo 2011-2026, 16 zips locais):
          # somente 2023 duplicou — 1 grupo residual, sem excess exato,
          # variando ID_DOC/LINK_DOC; todas as outras competencias fecharam
          # em 0. Caps 5/5. dt_receb marca a re-entrega do documento.
        - nome: bpa_con
          arquivo: "itr_cia_aberta_BPA_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 2500
          politica_dedup_silver: keep_first
          # TOLERADA (sweep completo 2011-2026, 16 zips locais): maximo=2.084
          # excess em 2024, todos os 1.618 grupos byte-identicos; 2023=1.754,
          # 2025=256 e 2026=160. Cap 2.500.
        - nome: bpa_ind
          arquivo: "itr_cia_aberta_BPA_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 4500
          max_grupos_residuais: 15
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep completo 2011-2026, 16 zips locais):
          # maximo exato=3.980 excess em 2024; maximo residual=9 grupos em
          # 2021 (162 excess exatos), variando somente VL_CONTA. Caps 4.500/15.
        - nome: bpp_con
          arquivo: "itr_cia_aberta_BPP_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5000
          max_grupos_residuais: 25
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido com probe_dataset direto, chave final):
          # 2024 = 324.556 linhas, excess exato=3.567 (2.772 grupos exatos), 16
          # grupos RESIDUAIS (VL_CONTA diverge no mesmo cnpj_cia+dt_refer+versao+
          # cd_conta+ds_conta+ordem_exerc — valores contraditos pela CVM, ver
          # _residuos.json — a re-medicao corrige o numero de grupos residuais
          # citado num comentario anterior, 18, obtido antes da chave final);
          # 2025 = 440 excess exato, 0 residuais. Cap excesso exato 5.000 (~1,4x
          # o maximo medido, 3.567); cap grupos residuais 25 (2024 mediu 16). Ver
          # ARCHITECTURE.md Sec 6.12 (chave_status contract).
        - nome: bpp_ind
          arquivo: "itr_cia_aberta_BPP_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 10000
          max_grupos_residuais: 22
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido com probe_dataset direto, chave final):
          # 2024 = 487.974 linhas, excess exato=6.989 (5.166 grupos exatos), 14
          # grupos RESIDUAIS (VL_CONTA diverge no mesmo cnpj_cia+dt_refer+versao+
          # cd_conta+ds_conta+ordem_exerc — valores contraditos pela CVM, ver
          # _residuos.json — corrige o numero de grupos residuais citado num
          # comentario anterior, 16); 2025 = 1.070 excess exato, 0 residuais. Cap
          # excesso exato 10.000 (~1,4x o maximo medido, 6.989); cap grupos
          # residuais 22 (2024 mediu 14). Ver ARCHITECTURE.md Sec 6.12 (chave_status contract).
        - nome: composicao_capital
          arquivo: "itr_cia_aberta_composicao_capital_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao]
          vigencia: { de: "2020" }
          chave_status: tolerada
          max_linhas_excedentes: 5
          politica_dedup_silver: keep_first
          # TOLERADA (re-medido 2026-09-08, zip atual 2021 no servidor):
          # 2021 = 2 excess (2 grupos, byte-identicos — par medido:
          # 02.291.077/0001-93, 2021-06-30, versao 1, duas vezes). Era
          # verificada por extrapolacao. Cap 5.
          # VERIFICADA (medido 2024/2025): 0 excess nas duas competencias.
        - nome: dfc_md_con
          arquivo: "itr_cia_aberta_DFC_MD_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 500
          politica_dedup_silver: keep_first
          # TOLERADA (medido 2024/2025): 2024 = 314 excess, 100% exatos;
          # 2025 = 0 excess. Cap 500 = ~1,6x o maximo medido.
          # dt_ini_exerc no fecha.
        - nome: dfc_md_ind
          arquivo: "itr_cia_aberta_DFC_MD_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 500
          politica_dedup_silver: keep_first
          # TOLERADA (medido 2024/2025): 2024 = 460 excess, 100% exatos;
          # 2025 = 14 excess, 100% exatos. Cap 500 = ~1,1x o maximo medido.
          # dt_ini_exerc no fecha.
        - nome: dfc_mi_con
          arquivo: "itr_cia_aberta_DFC_MI_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 1000
          politica_dedup_silver: keep_first
          # TOLERADA (medido 2024/2025): 2024 = 862 excess, 100% exatos;
          # 2025 = 122 excess, 100% exatos. Cap 1.000 = ~1,2x o maximo
          # medido. dt_ini_exerc no fecha.
        - nome: dfc_mi_ind
          arquivo: "itr_cia_aberta_DFC_MI_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 1500
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (sweep completo 2011-2026, 16 zips locais):
          # maximo exato=1.018 excess em 2024; maximo residual=8 grupos,
          # em 2021 e 2022, variando somente VL_CONTA. 2022 mediu 84 excess
          # exatos + 8 residuais; 2025=240 exatos. Caps 1.500/10.
        - nome: dmpl_con
          arquivo: "itr_cia_aberta_DMPL_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc, coluna_df]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 11000
          max_grupos_residuais: 80
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zip atual 2023 no
          # servidor): 2023 = 5.496 excess (4.600 exatos + 64 residuais
          # VL_CONTA). Residual 30 -> 80 (exato 11.000 segue com folga).
          # TOLERADA_COM_RESIDUO (re-medido com probe_dataset direto, chave final):
          # 2024 = 651.924 linhas, excess exato=7.833 (6.058 grupos exatos), 22
          # grupos RESIDUAIS (VL_CONTA diverge no mesmo cnpj_cia+dt_refer+versao+
          # cd_conta+ds_conta+ordem_exerc+coluna_df — a CVM publicou valores
          # contraditos, mesmo padrao de bpp_ind/dfc_mi_ind; ver _residuos.json);
          # 2025 = 912 excess exato, 0 residuais. ds_conta ja resolveu os grupos
          # de rotulo — os residuais sao valor, nenhuma chave resolve. Cap
          # excesso exato 11.000 (~1,4x o maximo medido, 7.833); cap grupos
          # residuais 30 (2024 mediu 22). Ver ARCHITECTURE.md Sec 6.12 (chave_status contract).
        - nome: dmpl_ind
          arquivo: "itr_cia_aberta_DMPL_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc, coluna_df]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 15000
          max_grupos_residuais: 70
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zips atuais 2021/2023
          # no servidor): 2021 = 723 excess (506 exatos + 47 residuais
          # VL_CONTA); 2023 = 5.772 (4.781 + 55). Residual 30 -> 70 (exato
          # 15.000 segue com folga).
          # TOLERADA_COM_RESIDUO (re-medido com probe_dataset direto, chave final):
          # 2024 = 731.777 linhas, excess exato=10.865 (8.018 grupos exatos), 22
          # grupos RESIDUAIS (VL_CONTA diverge); 2025 = 700.872 linhas, excess
          # exato=1.612 (1.460 grupos exatos), 4 grupos RESIDUAIS — corrige um
          # comentario anterior que dizia "2025 = 1.620 excess, 100% exatos": a
          # re-medicao direta contra o dado real mostra que 2025 tambem tem
          # residuo, so que menor. Ver _residuos.json. Cap excesso exato 15.000
          # (~1,4x o maximo medido, 10.865); cap grupos residuais 30 (2024 mediu
          # 22). Ver ARCHITECTURE.md Sec 6.12 (chave_status contract).
        - nome: dra_con
          arquivo: "itr_cia_aberta_DRA_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc, dt_ini_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 500
          politica_dedup_silver: keep_first
          # TOLERADA (medido 2024/2025): chave ALARGADA com dt_ini_exerc —
          # ITR traz 3 trimestres + comparativo no mesmo arquivo e a CVM
          # falha em deixar cd_conta consistente entre eles (antes 13.386
          # excess em 2024 e 12.864 em 2025, com grupos NAO exatos; agora
          # fecha). 2024 = 256
          # excess, 100% exatos; 2025 = 22 excess, 100% exatos. Cap 500 =
          # ~2x o maximo medido. dt_ini_exerc com 0 nulos.
        - nome: dra_ind
          arquivo: "itr_cia_aberta_DRA_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc, dt_ini_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 250
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zips atuais no
          # servidor): 2021 = 14 exatas + 4 residuais; 2023 = 176 exatas + 0
          # residuais (gate confirma; 140 grupos). O cap 25 veio da medicao
          # 2021 isolada — 2023 estava escondida atras de sumario truncado.
          # Caps 250/10.
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zip atual 2021 no
          # servidor): 2021 = 18 excess (14 exatos + 4 residuais VL_CONTA).
          # Status saiu de tolerada. Caps 25/10 (era 500/—).
          # TOLERADA (medido 2024/2025): chave ALARGADA com dt_ini_exerc
          # (mesma historia do dra_con; antes 13.648 excess em 2024 e 13.208
          # em 2025, grupos NAO exatos). 2024 = 302 excess, 100% exatos; 2025 = 38 excess,
          # 100% exatos. Cap 500 = ~1,7x o maximo medido. dt_ini_exerc com
          # 0 nulos.
        - nome: dre_con
          arquivo: "itr_cia_aberta_DRE_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc, dt_ini_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 2000
          politica_dedup_silver: keep_first
          # TOLERADA (medido 2024/2025): chave ALARGADA com dt_ini_exerc
          # (antes 66.750 excess em 2024 e 62.656 em 2025, grupos NAO
          # exatos — cd_conta nao era consistente entre os trimestres).
          # 2024 = 1.440 excess, 100% exatos; 2025 = 130 excess, 100%
          # exatos. Cap 2.000 = ~1,4x o maximo medido. dt_ini_exerc com
          # 0 nulos.
        - nome: dre_ind
          arquivo: "itr_cia_aberta_DRE_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc, dt_ini_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 1800
          max_grupos_residuais: 15
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zips atuais no
          # servidor): 2021 = 156 exatas + 12 residuais; 2023 = 1.582 exatas
          # + 0 residuais (gate confirma; 1.248 grupos). O cap 200 veio da
          # medicao 2021 isolada. Caps 1.800/15.
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zip atual 2021 no
          # servidor): 2021 = 168 excess (156 exatos + 12 residuais VL_CONTA).
          # Status saiu de tolerada. Caps 200/15 (era 3.000/—).
          # TOLERADA (medido 2024/2025): chave ALARGADA com dt_ini_exerc
          # (antes 96.378 excess em 2024 e 90.403 em 2025, grupos NAO
          # exatos). 2024 = 2.566 excess, 100% exatos; 2025 = 334 excess,
          # 100% exatos. Cap 3.000 = ~1,2x o maximo medido. dt_ini_exerc
          # com 0 nulos.
        - nome: dva_con
          arquivo: "itr_cia_aberta_DVA_con_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada
          max_linhas_excedentes: 1500
          politica_dedup_silver: keep_first
          # TOLERADA (medido 2024/2025): 2024 = 1.404 excess, 100% exatos;
          # 2025 = 200 excess, 100% exatos. Cap 1.500 = ~1,1x o maximo
          # medido. dt_ini_exerc no fecha.
        - nome: dva_ind
          arquivo: "itr_cia_aberta_DVA_ind_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, cd_conta, ds_conta, ordem_exerc]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 1800
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08 noite, zips atuais no
          # servidor): 2017 = 1 + 1; 2021 = 113 exatas + 6 residuais; 2023 =
          # 1.532 exatas + 0 residuais (1.210 grupos). O cap 150 veio das
          # medicoes 2017/2021 isoladas — 2023 estava escondida atras de
          # sumario truncado. Caps 1.800/10.
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zips atuais 2017/2021
          # no servidor): 2017 (congelado) = 2 excess (1 exato + 1 residual
          # VL_CONTA); 2021 = 119 (113 + 6). Status saiu de tolerada. Caps
          # 150/10 (era 3.000/—).
          # TOLERADA (medido 2024/2025): 2024 = 2.700 excess, 100% exatos;
          # 2025 = 432 excess, 100% exatos. Cap 3.000 = ~1,1x o maximo
          # medido. dt_ini_exerc no fecha.
        - nome: parecer
          arquivo: "itr_cia_aberta_parecer_{aaaa}.csv"
          chave: [cnpj_cia, dt_refer, versao, tp_relat_esp, tp_parecer_decl, num_item_parecer_decl]
          chaves_permitem_nulos: [tp_relat_esp]
          chave_status: tolerada_com_residuo
          max_linhas_excedentes: 5
          max_grupos_residuais: 10
          politica_dedup_silver: keep_first
          # TOLERADA_COM_RESIDUO (re-medido 2026-09-08, zip atual 2021 no
          # servidor): 2021 = 9 excess (2 exatos + 7 residuais variando
          # TXT_PARECER_DECL — mesmo padrao re-assinatura do DFP). Era
          # verificada por extrapolacao. Caps 5/10.
          # VERIFICADO: +tp_parecer_decl fecha em 0 excedentes (2024 e 2025),
          # mesmo padrao do cia_aberta_dfp/parecer — ver nota la.
          # CORRIGIDO: a chave declarava tp_relat_aud, copiado de cia_aberta_dfp.
          # Essa coluna NAO existe no ITR — o DFP traz TP_RELAT_AUD (relatorio de
          # auditoria) e o ITR traz TP_RELAT_ESP (revisao especial: o ITR e
          # revisao trimestral, nao auditoria completa). Verificado contra os
          # headers reais de itr_cia_aberta_parecer_2024/2025.csv; a fixture
          # tests/fixtures/headers/cia_aberta_itr__*.yml trava a regressao.