Visão executiva

Indicadores consolidados do andamento do projeto

Progresso geral
60%
Família E completa + P1+1 + S1.1.A read-only fechados
Decisões arquiteturais
34
D-1 a D-34 + D-IND_SIT (motor ICMS/IPI)
Gates PVA aprovados
2/2
D-20 (S1.0 — Tentativa 6) + D-20b (S1.0b — Tentativa 3)
Riscos ativos
3
YAML × normas desalinhados, D-22 CST saída, D-17 schemas CIAP

Linha do tempo

Sprints concluídos, em andamento e planejados

Concluído Em fechamento Em preparo Bloqueado Planejado

Famílias de correção

Estratégia de execução incremental por categoria de risco

Família E — Estrutural
Concluída

Marcação de retificadora (COD_FIN), recálculo do Bloco 9 com auto-referência, contadores X990 e propagação material controlada (C170 → C190 → C100; E110 → E116 com guarda de inversão de regime). Dois gates PVA reais aprovados — S1.0 (07/05) e S1.0b (08/05).

Família M-ICMS
Em curso

S1.1.A ✓ análise CST entrada read-only experimental fechada (66 testes, ~700 LOC). S1.1.B (próximo) habilita aplicação experimental — bloqueado por desalinhamento entre identificadores @norma: do YAML e filenames em docs/legislacao_md/.

Família CIAP
Bloqueado

Crédito do ativo permanente, parcela 1/48 e fator mensal de saídas tributadas. Aguarda extensão de schemas G110/G125 (TODO P0+1) antes do início. Estimativa revisada com base na velocidade real do S1.0/S1.0b.

Família IPI
Bloqueado

CST IPI, alíquota, base de cálculo e crédito de entrada. Aguarda extensão dos schemas C170 (P0+2) e E520 (P0+3). Estimativa revisada com base na velocidade real.

Riscos ativos

Situações que podem impactar prazo ou escopo

Identificadores @norma: do YAML não batem com filenames
Pré-requisito S1.1.B · Severidade alta

Validação E2E do S1.1.A revelou que IDs do YAML matriz_cst.yaml não casam por igualdade exata com arquivos em docs/legislacao_md/ — exemplos: Lei_Kandir_LC87_1996 vs LC_87_1996_Kandir.md; Convenio_ICMS_142_2018 vs Convenio_ICMS_142_2018_ST.md; Guia_Pratico_EFD_ICMS_IPI_v3 vs Guia_EFD_ICMS_IPI_v3.2.1.md. Consequência: toda recomendação sai com bloqueada=True e normas=(). Antes do S1.1.B é preciso alinhar os identificadores ou implementar alias map.

Decisão sobre escopo de CST de saída pendente
D-22 · Severidade média

Antes do Sprint S1.1.B avançar para CST de saída, é necessário decidir se a categoria C2 (CST ICMS) abrange saída. S1.1.A entregou apenas análise para CST de entrada — escopo recomendado pela documentação canônica P1+1. Se a decisão incluir saída, será necessária implementação de classificar_cst_icms_saida() ainda inexistente.

Schemas G110 e G125 ausentes do parser oficial
D-17 / P0+1 · Severidade média

Bloqueia Sprint S1.2 (Família CIAP). Extensão do REGISTRO_SCHEMAS conforme Guia Prático EFD ICMS/IPI precisa ser executada antes do início do sprint.

Próximos marcos

Cronograma realista com base na velocidade observada de S1.0 e S1.0b. Datas em dias úteis, ajustáveis conforme gates externos (decisões fiscais, entregáveis de identidade visual, validações PVA).

1
Alinhamento de identificadores @norma: ↔ filenames
Em planejamento · Pré-requisito do S1.1.B · Alinhar IDs do YAML matriz_cst com arquivos de docs/legislacao_md/ ou implementar alias map
2
Decisão D-22 — escopo do CST de saída
Aguardando · Habilita ou bloqueia classificar_cst_icms_saida() em S1.1.B · Impacta dimensionamento
3
Sprint S1.1.B — aplicação experimental M-ICMS
12 → 22/05/2026 · 4-6 dias úteis · Habilita modo experimental + dupla confirmação (D-21) sobre análise read-only do S1.1.A · Encerra com novo gate PVA → checkpoint v3.13.0-rc3
5
Sprint S1.2 — Família CIAP
25/05 → 08/06/2026 · 6-8 dias úteis · Pré-requisito P0+1 (schemas G110/G125) entra no início · Encerra com gate PVA real
6
Sprint S1.3 — Família IPI
08 → 18/06/2026 · 5-7 dias úteis · Pré-requisitos P0+2 (schemas C170 com IPI) e P0+3 (E520) · Encerra com gate PVA real
7
🏷️ Tag v3.13.0 oficial (sem sufixo)
~18 → 22/06/2026 · Após S1.0 + S1.0b + S1.1 + S1.2 + S1.3 todos validados em PVA real · Apto a sair da branch para o main
8
🚀 Merge em main + S2 (linguagem natural)
~25/06 → 02/07/2026 · 4-5 dias úteis · Branch da retificação volta para o tronco principal e S2 começa em ambiente unificado
9
Sprints S3-S4 + S5-S7 — pipeline + batch + audit + wizard
02/07 → 17/07/2026 · 13-16 dias úteis · Aprovação, pipeline PVA automático, batch, audit, wizard de uso

Tarefas pendentes e débito técnico

Pré-requisitos formais dos próximos sprints

YAML×MD
Alinhar identificadores @norma: em config/matriz_cst.yaml com filenames reais de docs/legislacao_md/, ou implementar alias map deterministico. Pré-requisito do S1.1.B — sem isso, todas as recomendações da matriz CST ficam bloqueadas (bloqueada=True, normas=()).
Antes do S1.1.B
D-22
Decisão pendente: a categoria C2 (CST ICMS) abrange CST de saída? S1.1.A entregou só análise de entrada; se a decisão incluir saída, S1.1.B precisa implementar classificar_cst_icms_saida().
Antes do S1.1.B
P1+1
Regra canônica de apuração ICMS documentada em tasks/REGRA_APURACAO_ICMS_S1_1.md. Define fórmula canônica do E110 conforme Guia v3.2.1: VL_ICMS_RECOLHER = VL_SLD_APURADO − VL_TOT_DED; DEB_ESP entra na coerência posterior com E116. Concluído em 08/05/2026 (commit dc17e69).
Concluído
P0+1
Estender REGISTRO_SCHEMAS do parser oficial com registros G110 e G125 (CIAP) conforme Guia Prático EFD ICMS/IPI.
Antes do S1.2
P0+2
Estender schema do registro C170 com campos IPI: CST_IPI, ALIQ_IPI, VL_IPI, VL_BC_IPI, COD_ENQ.
Antes do S1.3
P0+3
Confirmar registro E520 (apuração IPI) no Guia Prático e adicionar ao REGISTRO_SCHEMAS se necessário.
Antes do S1.3
T-1
Mover dataclasses ResultadoRetificacao e ModificacaoRegistro de motor.py para models.py compartilhado. Cleanup do ResultadoRetificacao órfão de app/core/models.py.
Antes do S2
T-2
Aplicar defesa em profundidade D-33 a motor.py (Contribuições): revalidação na entrada com TipoObrigacaoIncompativelError. Hoje só motor_icms_ipi revalida — chamadores diretos do motor de Contribuições dependem implicitamente do roteador.
Antes do S2
T-3
Substituir fixture sintética por EFD real anonimizada como gate D-20. Resolvido em 07/05/2026: Tentativa 6 do S1.0 incluiu registro 1010 obrigatório no Bloco 1 e foi ACEITA pelo PVA. Mesmo padrão usado para fechar S1.0b.
Concluído
P1+0
Extrair função de detecção de tipo de obrigação do dashboard para módulo compartilhado. Concluído em 04/05/2026 com refinamento P1+0.1 (consenso multi-sinal).
Concluído
L-31
Hardening em app/parsers/efd_icms_ipi.py: tentar ISO-8859-1 PRIMEIRO em parsers de EFD da ReceitaNetBX (Convênio ICMS 143/2006). Auto-detect probabilístico (chardet) gera replacement chars silenciosos em arquivos grandes.
Backlog

Decisões arquiteturais

Trinta decisões tomadas e registradas no plano canônico (drill-down técnico)

Decisões de escopo e arquitetura geral
D-3Detecção de tipo via estrutura, não COD_VER rígido
D-4Bloco 9 ICMS/IPI em arquivo separado do existente
D-9Motor universal em arquivo dedicado
D-12API e dashboard intocados no S1, exceto adapter P1+0
D-18Sprint S1 dividido em 4 famílias por risco
D-19Tipos secundários reservados para S1.4
D-30Tipo de retorno único ResultadoRetificacao
D-31Linguagem natural reservada para S2 (a ser registrada)
Decisões de tipo de dado e schemas
D-1aParser oficial: dict[str, list[tuple[str, str]]]
D-1bMotor: dict[str, dict[str, int]] derivado do parser
D-2Registry de funções: dict[str, Callable]
D-15Schemas compatíveis com REGISTRO_SCHEMAS oficial
D-17G110/G125 ausentes são GAP a sanar antes do S1.2
D-23Extensão do parser em P0+2 (IPI) e P0+3 (E520)
D-31Schemas cristalizam apenas índices tocados em cada sprint (0000 minimalista no S1.0)
Decisões de preservação byte-a-byte e robustez (D-24 e correlatas)
D-6Leitura em bytes brutos, decode localizado
D-24Arquivo retificado bit-idêntico exceto modificações
D-25Linha entra no diff só se conteúdo gerado difere
D-26Bloco 9 em ordem determinística documentada
D-27C190 falha explícita se campo não derivável
D-29Princípio de falha explícita
D-32ModificacaoRegistro.num_linha sempre 1-based real (delete=original, insert=retificado)
D-33Defesa em profundidade dupla: roteador + motor revalidam tipo de obrigação na entrada
D-34Guarda explícita DebEspNaoSuportadoError em S1.0b: motor falha ao tentar recalcular saldo com DEB_ESP > 0 até cobertura PVA específica
Decisões de processo, validação e versionamento
D-7Cobertura mínima 80% em módulos novos
D-10Tratamento de IND_SIT 3 com confirmação explícita
D-11@norma obrigatório por correção
D-14detectar_encoding extraído para módulo compartilhado
D-16Adapter de nomenclatura entre plano e codebase
D-20S1.0 fechado quando PVA real validar arquivo
D-21M-ICMS exige confirmação dupla e modo experimental
D-22Decisão sobre CST de saída antes do S1.1
D-28SemVer sem sufixo, rc1 e rc2 internos
D-IND_SITEFD ICMS/IPI altera COD_FIN, não IND_SIT

Sprints concluídos

Histórico de entregas com hashes de commits e principais resultados

P0 — Pavimentação · 5 relatórios + extração de detectar_encoding

Status: Concluído (GO COM RESSALVAS)

Commits: fc9bf85 · 734c8cf · 7ca75bb

Entregas: Mapeamento de tipos C1-C20, pré-condições normativas, cross-check de schemas, cobertura de utilitários ICMS, resultado consolidado. Identificou que 20 tipos do plano provisório precisavam ser reduzidos a famílias menores (D-18) e que vários schemas precisariam ser estendidos.

Lição-chave: P0 não é "rodar checks", é descoberta. Plano pós-P0 pode ser substancialmente diferente do plano pré-P0.

Pcanon — Plano canônico de retificação

Status: Concluído

Commit: dccd48b

Entrega: Documento de 731 linhas estabelecendo arquitetura, decisões D-1 a D-30, sequência S1.0 a S7, gotchas conhecidas e lições do P0. Vira fonte canônica que sprints seguintes referenciam.

P1+0 — Detector de tipo de obrigação SPED

Status: Concluído

Commits: f0049b4 · 85319fd · 34dd1f0 · f3d7321

Entrega: Módulo app/parsers/_detector_obrigacao.py com duas APIs (bytes e Path), adapter no dashboard preservando vocabulário legado, suite de testes com 30 casos, cobertura 93%. Cenário identificado: A (função pura existente, extração mecânica).

P1+0.1 — Correção de bug crítico no detector (consenso multi-sinal)

Status: Concluído

Commit: 6f8e5e9

Entrega: Refatoração do detector para usar voto por consenso em vez de early-return em sinal único. Bug detectado: fixture base do S1.0 era classificada como Contribuições por causa de DT_INI no campo 5 (sinal 2 disparava antes do sinal 1 de IND_PERFIL).

Lições registradas: L-DET-01 (early-return em sinal único é falso-positivo esperando para acontecer); L-DET-02 (fixtures podem mascarar bugs); L-DET-03 (preservar comportamento durante extração não significa preservar bugs no canônico).

S1.0 — Motor estrutural mínimo (família E) · gate D-20 APROVADO

Status: Concluído (Tentativa 6 ACEITA pelo PVA real em 07/05/2026)

Commits principais: a34f054 (recálculo Bloco 9) · 67d2608 (E1/E2/E3) · e474b56 (motor com defesa em profundidade) · 6841023 (motor universal — roteador) · 0ea68e3 (E2 num_linha real) · 36d4c7e (suite final byte-a-byte) · a7d1e4e (Tentativa 6 — registro 1010 obrigatório) · 8999b32 (Tentativa 6 ACEITA — gate D-20 fechado)

Entregas: motor de retificação EFD ICMS/IPI completo para a família estrutural — marcação de retificadora via COD_FIN (D-IND_SIT), recálculo determinístico do Bloco 9 com auto-referência (D-26), correções E1/E2/E3 estruturais, motor universal com roteamento Contribuições↔ICMS/IPI, suite de testes byte-a-byte completa.

Caminho até o gate D-20: 6 tentativas no PVA. Tentativa 5 confirmou (b9ebe30) que fixtures sintéticas mínimas "nascem condenadas" — solução foi usar EFD real anonimizada com registro 1010 obrigatório (Tentativa 6).

Hash do arquivo aceito: 28cbc41d…0825cf713c · Checkpoint: tag v3.13.0-rc1 (anotada).

S1.0+1 — Cristalização das decisões emergentes

Status: Concluído (07/05/2026, commit 3371c9c)

Entrega: três decisões arquiteturais que emergiram da execução do S1.0 e foram cristalizadas no plano canônico para guiar sprints subsequentes.

Decisões cristalizadas:

· D-31 — schemas do motor cristalizam apenas os índices dos campos efetivamente tocados em cada sprint (ex: 0000 minimalista no S1.0 — só REG/COD_VER/COD_FIN). Razão: layouts variam por versão do Guia e por perfil de obrigação; cristalizar com base em fixture sintética não-padrão gera falso positivo (L-DET-01/02/03 do P1+0.1).

· D-32ModificacaoRegistro.num_linha declara sempre posição real 1-based (no original para deletes, no retificado para inserts). num_linha=0 proibido. Reordenações = par delete+insert; duplicatas removidas declaradas na posição da duplicata.

· D-33 — defesa em profundidade dupla na detecção de tipo de obrigação: motor_universal valida no roteador e cada motor especializado revalida na entrada. motor_icms_ipi ✓; motor.py (Contribuições) pendente — TODO T-2.

P1+1 — Regra canônica de apuração ICMS

Status: Concluído (08/05/2026, commit dc17e69)

Entrega: documento canônico tasks/REGRA_APURACAO_ICMS_S1_1.md separa propagação estrutural S1.0b, mérito fiscal S1.1 e ajustes E111. Define a fórmula canônica do E110 conforme Guia v3.2.1: VL_ICMS_RECOLHER = VL_SLD_APURADO − VL_TOT_DED; DEB_ESP entra na coerência posterior com E116.

Recomendações fixadas: C2 inicial cobre apenas CST de entrada (D-22 mantida pendente); C18/E111 fica bloqueado até validar a ordem real do E111 contra Guia + SPED real.

Consequência imediata: revelou bug latente no S1.0b — _recalcular_saldos_e110 somava DEB_ESP em VL_ICMS_RECOLHER, divergindo da fórmula canônica. Mitigado por D-34 (guarda DebEspNaoSuportadoError, commit d9d616e) e registrado como L-35.

S1.1.A — Análise CST entrada read-only experimental · FECHADO

Status: Concluído (08/05/2026, commit final fa1021d)

Commits principais: bc2c8bc (dataclasses ContextoCSTEntrada e RecomendacaoCSTEntrada) · bf54c81 (analisar_cst_icms_entrada read-only com resolução de @norma:) · 326f72f (testes E2E sem mocks contra matriz e docs/legislacao_md/ reais) · fa1021d (registro de saída e critérios de aceite atendidos)

Entregas: ~700 LOC totais (incluindo testes), 66 testes em tests/test_analise_cst_entrada.py. Análise read-only que examina CST de entrada e gera RecomendacaoCSTEntrada com normas resolvidas via registry.

Bloqueio identificado: identificadores @norma: do YAML não casam por igualdade exata com filenames em docs/legislacao_md/ — exemplos: Lei_Kandir_LC87_1996 vs LC_87_1996_Kandir.md; Convenio_ICMS_142_2018 vs Convenio_ICMS_142_2018_ST.md. Consequência: toda recomendação hoje sai com bloqueada=True e normas=(). Pré-requisito explícito do S1.1.B.

Critérios de aceite: 13/13 atendidos (incluindo workaround documentado para CPython gh-91054, isolamento via monkeypatch, validação E2E sem mocks).

S1.0b — Propagação estrutural do motor ICMS/IPI · gate PVA APROVADO

Status: Concluído (Tentativa 3 ACEITA pelo PVA real em 08/05/2026 12:48)

Commits principais: 3d6c2f7 (schemas e erros) · 86d7454 (primitivo de alteração material) · 7b5aecb (propagação C170→C190) · 11414d8 (delta E110) · a90dcca (integração ao motor) · d9b98f5 (propagação C170→C100 pai) · 4a5aff1 (propagação E110→E116 com guarda) · aa2acd2 (integração C100/E116) · ac3e7a7 (Tentativa 3 — propagações C100/E116) · bae76b2 (gate PVA fechado)

Entregas: motor expandido para suportar propagação estrutural quando o operador altera materialmente um C170. Whitelist estrita do primitivo AlteracaoMaterialControlada (apenas C170.VL_ICMS, linha_sped > 0, Decimal finito não-negativo). Cinco propagações documentadas:

· _aplicar_alteracao_c170_e_c190 — altera C170, propaga delta para o C190 do grupo

· _aplicar_propagacao_c100 — propaga delta para o C100 pai

· _aplicar_delta_e110 — atualiza E110, recalcula saldos, com guarda contra inversão de regime (DeltaApuracaoNaoSuportadoError)

· _aplicar_propagacao_e116 — propaga delta de obrigação para E116, com RegistroE116AusenteError em caso de ausência

Hash do arquivo aceito: 81356267…0825cf713c · Checkpoint: tag v3.13.0-rc2 a criar nesta semana.

Lições recentes capturadas

Aprendizados convertidos em regra preventiva nas últimas duas semanas

L-35 — Validação PVA com fixture de campo zerado mascara divergência da fórmula canônica

Domínio: qualidade · apuração ICMS · S1.0b · Data: 08/05/2026 · Commit: b694c8d

Erro: S1.0b foi validado no PVA com fixture-base contendo DEB_ESP=0. A função interna _recalcular_saldos_e110 derivava VL_ICMS_RECOLHER somando DEB_ESP ao saldo apurado, divergindo da fórmula canônica P1+1 (VL_ICMS_RECOLHER = VL_SLD_APURADO − VL_TOT_DED). PVA aceitou silenciosamente porque DEB_ESP=0 torna a divergência invisível.

Causa raiz: validação PVA com fixture mínima não exercita campos opcionais não-zero. Reverse-engineering de helpers antigos sem cristalizar a fórmula canônica primeiro.

Mitigação aplicada: D-34 (guarda explícita DebEspNaoSuportadoError, commit d9d616e) — motor falha de forma controlada ao receber DEB_ESP > 0 até cobertura PVA específica.

Regra preventiva: validar PVA com cobertura de cenários (DEB_ESP, VL_TOT_DED, ajustes E111, estornos, saldo credor anterior) — não apenas com fixture mínima. Cristalizar fórmulas canônicas em documento separado antes de implementar. Preferir guarda explícita (raise) a comportamento incorreto silencioso.

L-31 — ISO-8859-1 é canônico em EFDs ICMS/IPI da ReceitaNetBX

Domínio: parsing / qualidade · Data: 06/05/2026 · Commit: 78ef416

Erro: Auto-detect chardet retornou None com confidence 0,95 em EFDs grandes — pipeline gravou replacement chars () no Parquet/XLSX. Quebra de qualidade em entregas a clientes (SIB, HueHoco): ?LEO DE CORTE, M?QUINA, AQUISI??O.

Causa raiz: EFDs ReceitaNetBX são padronizadas em ISO-8859-1 (Latin-1) pelo Convênio ICMS 143/2006 + tooling SEFAZ. Confiar em auto-detect probabilístico em arquivo padronizado é over-engineering com regressão silenciosa.

Regra preventiva: em parsers de EFD, tentar iso-8859-1 PRIMEIRO; só cair em outras codificações se houver erro real. Validar pós-decodificação a contagem de — se >0, decode está errado mesmo sem exceção.

L-32 — chunking glob → rglob para indexar subdirectórios da base normativa

Domínio: RAG / normas · Data: 06/05/2026 · Commit: c96eb36

Causa raiz: base_dir.glob("*.md") não visita subdirectórios. 14 normas catalogadas em estadual/sp/portaria_sre/, decretos/, leis/ existiam há meses sem ser indexadas pelo BM25.

Regra preventiva: sempre usar rglob em walkers de bases normativas hierárquicas. Adicionar smoke test que conta arquivos por subdiretório.

L-33 — CST 70 não pertence à lista _CST_NUNCA_GERADORA

Domínio: e-CredAc · Data: 06/05/2026 · Commit: 3edc238

Causa raiz: CST 70 (tributado com redução de BC e cobrança por ST) tem manutenção de crédito específica por norma — não bloqueia geração de crédito acumulado de forma absoluta. Inclusão indevida em _CST_NUNCA_GERADORA bloqueava classificação Inciso II.

Regra preventiva: "nunca geradora" deve listar APENAS CSTs que explicitamente excluem manutenção de crédito (CST 50 — suspensão; CST 90 — outros sem manutenção). Demais CSTs são tratados condicionalmente no bloco do Inciso II.

L-34 — Valores absolutos fiscais não devem aparecer em mensagens de exceção (LGPD)

Domínio: segurança / LGPD · Data: 06/05/2026 · Commit: 3edc238

Causa raiz: reconciliador_blocos.py incluía valores absolutos de saldo credor nos campos detalhes e fontes de divergência. Logs com saldo credor expostos violam diretriz LGPD do projeto (regra 8 do CLAUDE.md).

Regra preventiva: em campos de exceção, log ou detalhe, usar valores de divergência (R$ 0,02), faixas (>1mi, 100k–1mi) ou referências sem valor absoluto ("[ver EFD]"). Nunca expor saldo_credor_fim, parcela_ca ou ICMS total em mensagens.