# sowai-fiscal Núcleo fiscal puro da SowAI: motor de regras tributário (imposto-como-dado), chave de acesso de NF-e (módulo 11) e builder do XML NF-e 55 (leiaute NT 2025.002 v1.40, bindings `nfelib` 2.5.x). Extraído do produto `sowai-auto` (F1 do plano `sowai-fiscal-svc`) como lib versionada — zero I/O, zero SQLAlchemy, zero FastAPI, zero acoplamento a nenhum produto: a interface com o ORM do consumidor é o `Protocol` estrutural `sowai_fiscal.types.TaxRuleLike`. ## Módulos - `domains` — catálogo `TaxDomain`/`DOMAIN_FIELDS`/`MATCHER_WEIGHTS` + transposição de CFOP intra→interestadual. - `chave_acesso` — DV módulo 11, sorteio de `cNF`, montagem da chave de 44 dígitos. - `tpag` — tabela de códigos `tPag` (MOC, grupo YA02). - `presets` — presets fiscais seed-editáveis (perfis reais extraídos do iCode da Thiago Auto Center). - `resolver` — `resolve_fiscal`: `FiscalOperation` × regras (`TaxRuleLike`) → `FiscalResult`. Puro, determinístico, fail-closed. - `xml_builder` — `build_nfe`: `DadosEmissao` (já resolvido) → objeto `Nfe` (bindings `nfelib`). - `types` — `TaxRuleLike`, o `Protocol` que desacopla o resolver do ORM do produto. - `golden_helpers` — `dados_from_json`/`serialize_infnfe`, usados pelo corpus golden (`goldens/`) e pelo teste de paridade do produto consumidor. ## Corpus golden `src/sowai_fiscal/goldens/caso_.{input.json,expected.xml}` — pares determinísticos (`dh_emi`/`cnf`/`chave_acesso` pinados no input) que travam o leiaute XML pré-assinatura gerado a partir de um `DadosEmissao`. São dados de pacote (lidos via `importlib.resources`), para que o produto consumidor compare byte a byte contra os MESMOS arquivos da lib instalada — nenhuma cópia que possa divergir. Regenerar com `uv run python scripts/gen_goldens.py` apenas quando uma NT mudar o leiaute DE PROPÓSITO. ## Testes ```bash uv sync uv run pytest ``` 100% local — sem Postgres, sem k8s. ## Versionamento (contrato) - **SemVer estrito.** Os nomes públicos (`resolve_fiscal`, `build_nfe`, `montar_chave_acesso`, `TaxDomain`, `DOMAIN_FIELDS`, `MATCHER_WEIGHTS`, `PRESETS`, `TPAG_CODES`, `DadosEmissao` e sub-dataclasses, `FiscalOperation/FiscalItem/ FiscalResult/TributoLinha`, exceções) são O CONTRATO — mudança incompatível = major. - **Consumidores pinam por TAG, nunca por branch**: `uv add "sowai-fiscal @ git+https://git.sowai.com.br/jonatan/sowai-fiscal.git@vX.Y.Z"` (o lock pina o hash). - Goldens mudam SÓ quando uma NT muda o leiaute de propósito (ver seção acima) — e isso é sempre pelo menos um minor, com nota de release explicando a NT. ## Gap conhecido (registrado na F1, 2026-07-17) - **Grupo ANP (`gProdANP`) não é emitido** — `ItemData`/builder não têm o campo. NF-e de óleo lubrificante SEM esse grupo é REJEITADA pela SEFAZ. Fechar na cobertura R1 (junto do cClassTrib) ANTES de homologar o caso Óleos na F4. O golden `caso_st_intra` cobre ICMS-ST/CSOSN 500, NÃO cobre ANP.