8.7 KiB
Determinação segura do cClassTrib (resolver determinístico)
central/app/cclasstrib_resolver.py (puro, sem Firebird, sem rede, sem probabilidade) + central/app/rtc_reference_data.py (gerado por scripts/build_rtc_reference_data.py, com hash).
ACCESSED_AT: 2026-09-24/25. Nada aqui é chute: uma classe só é proposta quando uma regra explícita, ancorada nos textos oficiais, a prova.
Fontes oficiais (SOURCE / DOCUMENT / VERSION / PUBLICATION / SHA256)
| Fonte | Documento | Versão / publicação | SHA256 |
|---|---|---|---|
| Portal Nacional NF-e (ENCAT) | Tabela cClassTrib (164 classes, 18 CST) — cClassTrib 2026-06-22.xlsx |
publicada 22/06/2026; no repo em sources/raw/bootstrap_v1/ e no Hub (dataset RTC_CCLASSTRIB ACTIVE) |
1448cb63a41bdb67… |
| Planalto (cópia do Internet Archive; planalto.gov.br recusa conexão direta) | LC 214/2025 compilada (com LC 227/2026: Anexo XIV revogado) — arts. 125–152 (reduções), 172 (combustíveis), 348 (2026); Anexos I–XV | acessado 2026-09-24 | 5c7d59b3c49e5b7c… |
| Portal Nacional NF-e | NT 2025.002-RTC v1.51 (04/08/2026) — para CRT 1/2/4 as orientações de IBS/CBS "serão publicadas em NT futura"; tributação a partir de 2027 (LC 214 art. 348) | https://www.nfe.fazenda.gov.br/portal/exibirArquivo.aspx?conteudo=AKD/muSmiIY= |
ver docs/sources/SOURCES_MANIFEST_UNIFIED_FISCAL_V1.json |
| SGV 5.1.0.4 (executável) | tela de produto: cClassTrib = TRzDBButtonEdit DataField=CCLASSTRIB; consulta select * from RTC_CCLASSTRIB where … (IND_NFE=1 or IND_NFCE=1 or IND_CTE=1); junção do documento C000025.CCLASSTRIB → RTC_CCLASSTRIB → RTC_CST |
binário local | — |
O portal NF-e foi rastreado (Documentos, Diversos, Atos): não expõe tabela cClassTrib mais nova que 22/06/2026. Não há endpoint oficial NCM→cClassTrib: o vínculo vem dos Anexos da LC 214 (listas de NCM) + tabela oficial.
O que o SGV faz (item 5) — DOCUMENT_CCLASSTRIB_SOURCE
O SGV não tem regra produto→cClassTrib: o operador escolhe a classe pelo botão de busca (filtrada por IND_NFE/IND_NFCE/IND_CTE=1) e o documento usa C000025.CCLASSTRIB diretamente, juntando ao catálogo local e ao CST. Nenhuma trigger/procedure referencia RTC; USAR_REFORMA_TRIBUTARIA só liga/desliga. Consequência: qualquer resolução automática é regra nossa, portanto tem de ser provada e auditável. A classe proposta tem de passar no mesmo filtro do SGV (usável em NF-e/NFC-e).
Catálogo local × oficial (item 4) — RTC_LOCAL_OFFICIAL_COMPATIBILITY
Comparação por código (CST, reduções IBS/CBS, indicadores NF-e/NFC-e, vigência): MATCH | LOCAL_ONLY | OFFICIAL_ONLY | MISMATCH | EXPIRED. Nada é escrito no catálogo local.
| TESTESOFICIAIS (= todos os bancos com RTC, mesmo catálogo) | |
|---|---|
| MATCH | 131 |
| OFFICIAL_ONLY (local desatualizado) | 19 (000005, 200053, 200054, 221002-4, 400002, 410032-7, 550022-5, 620007, 820009) |
| MISMATCH | 11 — só DOCUMENT_FLAGS (IND_NFE/IND_NFCE): 200001, 200044, 410027, 410028, 410031, 550002, 620001-5 |
| EXPIRED presentes no local | 3 (220001-3, fim 01/01/2026) |
| LOCAL_ONLY | 0 |
Conclusão: LOCAL_CATALOG_HAS_ENOUGH_METADATA_TO_RESOLVE = false. O catálogo local (33 colunas: CST, tipo de alíquota, reduções, indicadores de documento, monofasia, ANEXO, LINK) descreve a classe, não contém NCM nem critério de produto: só o ANEXO liga classe a anexo. A determinação usa o catálogo local para validar e os Anexos da LC 214 para decidir. Incompatibilidade material ⇒ só a classe afetada é bloqueada (RTC_LOCAL_CATALOG_OUTDATED / CCLASSTRIB_OFFICIAL_MISMATCH); as classes que as regras usam (000001, 200003, 200014, 200034, 200035) são MATCH.
Modelo de resolução e regras
Premissa documentada: venda ordinária no mercado interno (default de produto). Classes que dependem do adquirente/operação (órgão público, exportação, ZFM/ALC, crédito presumido, diferimento…) não cabem num default de produto ⇒ AMBIGUOUS.
| Regra | Condição | Status |
|---|---|---|
| RTC-R0 | RTC desligada no ERP | NOT_APPLICABLE |
| RTC-G1 | catálogo RTC local com falha de integridade | INSUFFICIENT_EVIDENCE |
| RTC-R1 | Simples (CRT 1/2/4) ou regime desconhecido | INSUFFICIENT_EVIDENCE (NT 2025.002: orientação pendente) |
| RTC-R2 | NCM sem confirmação de 8 dígitos válidos | INSUFFICIENT_EVIDENCE |
| RTC-A1 | NCM em anexo revogado, em anexo sem classe-padrão única (IV, V, VI, IX, X, XI, XII, XIII…) ou sob texto condicional ("exceto", "em conformidade com…", "ressalvados…") | AMBIGUOUS |
| RTC-A2 | NCM listado em mais de um anexo | AMBIGUOUS |
| RTC-A3 | capítulos 01–14, 27, 30, 49, 71, 87, 88, 89, 90 e posições 9619, 2207, 3826, 8703: regime definido pela natureza/operação do bem | AMBIGUOUS |
| RTC-R3 | NCM em exatamente um anexo com classe-padrão única (I→200003, VII→200034, VIII→200035, XV→200014) e item sem condição |
RESOLVED_WITH_EXPLICIT_RULE |
| RTC-R4 | NCM em nenhum anexo e fora dos capítulos acima ⇒ tributação integral (regra geral, LC 214 art. 4). Exclusão residual não é evidência positiva | SUGGESTION_ONLY → 000001 (nunca candidato de escrita) |
| RTC-G2 | classe proposta ausente/diferente no catálogo local, fora de vigência ou inutilizável em NF-e/NFC-e | INSUFFICIENT_EVIDENCE |
RESOLVED_DETERMINISTIC (regra sem premissa de operação) não é usado: toda resolução carrega a premissa "venda ordinária" e por isso é RESOLVED_WITH_EXPLICIT_RULE.
Saída auditável: status, resolved_cclasstrib, resolved_cst_ibscbs, reason, rule_id, confidence_type (ANNEX_TEXT_MATCH | EXCLUSION_OF_ALL_SPECIAL_REGIMES; sem score), inputs_used, evidence (item do anexo, prefixo, texto), source_references (sha256).
O anexo é lido do texto oficial por scripts/build_rtc_reference_data.py (item a item; clean=False quando há condição). verify_annex_class_map() prova contra a tabela oficial que cada classe-padrão existe, é a única classe do anexo usável em NF-e/NFC-e e tem o ANEXO esperado (o Anexo IX ficou de fora: a classe 515001 é irmã).
Blockers RTC (uma causa raiz, um blocker por produto)
CCLASSTRIB_MISSING (com READY_TO_APPLY:<classe>:<regra> quando a regra prova a classe) · CCLASSTRIB_MISSING_UNRESOLVED (cClassTrib não determinado) · CCLASSTRIB_AMBIGUOUS (cClassTrib ambíguo) · RTC_RULE_EVIDENCE_MISSING (evidência fiscal insuficiente) · RTC_LOCAL_CATALOG_OUTDATED (catálogo RTC local incompatível) · CCLASSTRIB_OFFICIAL_MISMATCH (classe existente diverge do oficial) · CCLASSTRIB_CONFLICT (valor existente ≠ regra determinística) + os de validação (INVALID_FORMAT, NOT_IN_CATALOG, RTC_CST_MISSING, RTC_CATALOG_INVALID). Todos vão para a mesma fila (categoria RTC).
Dry-run real (somente leitura; scripts/rtc_resolution_dryrun.py → docs/runs/rtc_resolution_dryrun.json, amostra de 100 em docs/runs/rtc_resolution_audit_sample.csv)
Estado como está hoje: TESTESOFICIAIS e CONSTRUCAO têm RTC ligada e regime Simples ⇒ 0 candidatos (RTC-R1). Simulação "regime normal + RTC ligada" (o que as regras resolveriam quando existir orientação oficial para Simples):
| Banco | Produtos | Prontos (R3+R4) | Ambíguos | Insuficientes (NCM inválido) |
|---|---|---|---|---|
| TESTESOFICIAIS | 521 | 280 | 215 | 26 |
| CONSTRUCAO | 3.712 | 2.725 | 973 | 14 |
| MMMODAS | 20.996 | 20.831 | 49 | 116 |
| RINCAO (CRT 3, RTC off no banco) | 894 | 530 | 364 | 0 |
| UNIAO | 8.942 | 7.419 | 1.432 | 91 |
Limitações
Simples fica bloqueado até haver orientação oficial (ou decisão explícita de empresa, não implementada); operações especiais não são cobertas pelo default de produto; a extração dos anexos é textual (itens condicionais viram ambíguos de propósito); o catálogo oficial usado é o de 22/06/2026; sem autorização, nada é escrito (ver docs/rtc_auto_apply.md).
Classes de regra (rtc-rules-v2)
AUTO_APPLY_SAFE (única hoje: RTC-R3, CRT 3, anexo único, item limpo, classe MATCH_SAFE) · VALIDATION_ONLY (R0 RTC desligada, valida valor existente) · SUGGESTION_ONLY (R4) · BLOCKED_BY_EVIDENCE (R1 Simples/regime desconhecido, R2 NCM inválido, A1–A3 ambíguo, G1/G2 catálogo). Escrita só com evidência POSITIVA explícita: nunca por similaridade, frequência, LLM ou "não achei nada mais". Vigência local vs oficial: início diferente com a classe em vigor nos dois lados é informativo (MATCH_SAFE); fim local agendado = MATCH_WITH_NON_MATERIAL_DIFFERENCE (não escreve); início futuro ou fim vencido = MISMATCH. Fontes: docs/sources/RTC_OFFICIAL_ACTS_MANIFEST_V2.json. Escrita/aprovação/rollback: docs/rtc_auto_apply.md.