Files
GTI_GERENCIADOR_FISCAL/docs/rtc_auto_apply.md
T

38 lines
4.7 KiB
Markdown

# cClassTrib — preenchimento controlado centralmente (RTC_CCLASSTRIB_WRITE_V1)
O Agent **nunca** decide sozinho escrever no ERP. Não há chave local (`agent.env`, `FIREBIRD_WRITES`, PowerShell, RDP): a autorização vem **somente** dentro do job autenticado enviado pelo Hub. O Agent expõe apenas a capability restrita `RTC_CCLASSTRIB_WRITE_V1` (heartbeat).
## Modos (por instalação, painel: Agent → "Controle e candidatos cClassTrib")
| Modo | Efeito |
|---|---|
| `DISABLED` (padrão) | só informa; nada de preview, nada de escrita |
| `DRY_RUN` | calcula e envia o preview dos candidatos; zero escrita |
| `APPROVAL_REQUIRED` | escreve só os produtos aprovados por um humano no painel (lote de até 500 por job) |
| `ENABLED` | escreve os candidatos determinísticos (até `RTC_AUTO_APPLY_MAX_PER_JOB`, padrão 500, por job); exige digitar `PREENCHER` |
Texto do painel: "Somente cClassTrib com regra fiscal determinística e catálogo validado pode ser preenchido automaticamente."
Mudança de modo = evento de auditoria administrativa (`RTC_WRITE_MODE`). Migration `0028_rtc_write_modes` (padrão `DISABLED`; instalações que já tinham a autorização 0027 viram `ENABLED`).
## O que pode ser escrito
Somente `C000025.CCLASSTRIB` (allowlist `ALLOWED_RTC_WRITE_FIELDS`), somente quando **todos** valem: RTC ligada no ERP; regra `AUTO_APPLY_SAFE` (hoje só **RTC-R3**: NCM em exatamente um anexo I/VII/VIII/XV da LC 214, item limpo, CRT 3, uma única classe); classe `MATCH_SAFE` no catálogo local vs oficial; CST válido; empresa relida (`C000004.CRT` = único valor esperado e = 3); RTC/parâmetro/catálogo relidos; produto inalterado (NCM + descrição + valor, fingerprint); valor atual vazio. **R4 (exclusão residual → 000001) é só sugestão e nunca vira candidato.** Nunca sobrescreve: valor igual → `NO_WRITE_REQUIRED`; diferente → `CCLASSTRIB_CONFLICT` (bloqueio). Qualquer gate falho → zero escrita para aquele produto.
Sequência por produto (uma transação curta): reler tudo → recalcular a decisão → conferir fingerprint → `UPDATE C000025 SET CCLASSTRIB = ? WHERE CODIGO = ? AND (CCLASSTRIB IS NULL OR TRIM(CCLASSTRIB)='')` → rowcount = 1 → reler → commit → auditoria.
## Preview e aprovação
O Agent envia os candidatos (até 5.000 por job; `preview_truncated` sinaliza excesso) → tabela `rtc_candidates` (PENDING/APPROVED/REJECTED/APPLIED/STALE). O painel pagina no servidor (50/página), filtra por status, aprova/rejeita selecionados ou todos os pendentes e dispara "Aplicar aprovados agora". Uma proposta que muda invalida a aprovação anterior; produto que deixa de ser elegível numa avaliação completa vira `STALE`.
## Auditoria (append-only, `rtc_write_audits`)
cliente, agent, `installation_uuid`, produto, snapshot da descrição, campo, valor antigo/novo, regra + versão (`rtc-rules-v2`), evidência, hashes/versões das fontes oficiais, hash e estado (`MATCH_SAFE`) do catálogo local, status RTC, CRT da empresa, timestamp, job, origem da autorização (`HUB_MODE:<modo>`), resultado, ação (`APPLY`/`ROLLBACK`). Identidade vem do contexto autenticado, nunca do payload. Sem segredos.
## Rollback por registro
Painel → "Reverter" (digitar `REVERTER`) marca o registro `REQUESTED` e cria um job; o Hub entrega `{audit_id, product_code, written_value}` no job. O Agent só restaura (`SET CCLASSTRIB = NULL`) se o valor atual **ainda for igual ao gravado**; senão `ROLLBACK_CONFLICT_VALUE_CHANGED` (nada muda). Um único statement fixo, sem SQL livre. O registro original vira `DONE`/`BLOCKED`; o produto volta a ser candidato.
## Validação
- Testes: `agent/tests/test_rtc_auto_apply.py`, `central/tests/test_zero_touch_hub.py`, `test_control_panel_pages.py`, `test_rtc_security.py`, `test_cclasstrib_resolver.py`.
- **E2E em CÓPIA** (`scripts/rtc_copy_write_e2e.py`, `docs/runs/rtc_copy_write_e2e.json`): restaura a cópia do `.fbk`; DISABLED/DRY_RUN/decisão obsoleta = 0 escrita; aprovação de 5 → exatamente 5; ENABLED → 77 (total); reler; FK/CST órfãos 0; segunda execução 0; rollback de 3 + 1 conflito recusado; reaplicação de 3; idempotência 0; hash de 324 tabelas: `NON_TARGET_COLUMNS_CHANGED=0`, `CATALOG_CHANGED=0`, `PARAMETERS_CHANGED=0`, `DOCUMENT_TABLES_CHANGED=0`, nenhuma outra tabela alterada.
- Escala (`scripts/scale_hub_test.py`, 21.000 produtos, payload 7,96 MB): persistência 43 s → 5,5 s (upsert em lote; regime estável 64 statements); painel < 0,6 s.
- Bancos reais: 0 escritas, 0 tentativas.
## Limitações
Simples continua bloqueado (sem orientação oficial: NT 2025.002 v1.51; Ato Conjunto RFB/CGIBS 4/2026 fixa a obrigação de Simples em 2027-01-01). Regras além de R3 exigem evidência positiva nova. O Agent 2 permanece em `DISABLED`.