Files
GTI_GERENCIADOR_FISCAL/docs/rtc_auto_apply.md
T

47 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.
## Reautorização imediata antes da escrita (1.2.1)
O modo entregue no job pode envelhecer (operador desativa durante um lote). Antes de **cada** UPDATE o Agent relê a autorização atual no Hub (`GET /v1/agents/me/authorizations`, autenticado pelo token do próprio Agent; devolve só modo, aprovados e reversões da sua instalação; cache de 3 s). Se o modo mudou, se o produto perdeu a aprovação ou se o Hub não puder ser consultado, o produto é interrompido **sem escrever** (`AUTHORIZATION_CHANGED` / `AUTHORIZATION_UNVERIFIABLE`). Autorização não confirmada não é autorização.
## Quem pode mudar o que (RBAC, 1.2.1)
A identidade vem do SSO do GTI Gerenciador (`perfil`). **ADMIN** (e contas LOCAL de emergência) pode: `APPROVAL_REQUIRED`/`ENABLED`, aprovar/rejeitar, aplicar aprovados e reverter. Um colaborador **PADRAO** só vê a página e alterna `DISABLED`/`DRY_RUN` (somente leitura); tentativas restritas devolvem 403 e ficam auditadas (`RTC_DENIED`). Sair de um modo de escrita também é restrito a ADMIN. Toda mudança de modo, aprovação e reversão grava o operador e o perfil no evento de auditoria.
## Backpressure de jobs pesados (1.2.1)
`HEAVY_JOB_CONCURRENCY_LIMIT` (padrão 3; `<=0` desliga): no máximo N jobs `INITIAL_SYNC`/`REPROCESS_ALL` rodam ao mesmo tempo em **todos** os Agents; os demais ficam `PENDING` (fila) e o Agent segue com heartbeat e polling. Um job leve nunca fica preso atrás de um pesado. Job RUNNING há mais de 1 h não ocupa vaga. Medição (8 Agents × 1.042 produtos, Hub de desenvolvimento): sem limite 51,9 produtos/s, CPU pico 149%, cada Agent até 160 s; com limite 3: 66,7 produtos/s, CPU pico 116%, cada Agent até 45 s (espera máx. 88 s), 0 falhas.
## 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`.