Files
GTI_GERENCIADOR_FISCAL/docs/CFOP_IPPT_WRITE_CAPABILITY_V1.md
T
gtiandClaude Sonnet 5 3e3858054f feat: CFOP/IPPT write-capability core (inert, not wired, not activated)
Missao 3 / Bloco C.1-C.2: new agent/src/gti_fiscal_agent/cfop_ippt_auto_apply.py
mirrors the existing rtc_auto_apply.py safety model for a new, narrower
capability (CFOP_IPPT_WRITE_V1): compare-before-write, stale-write guard
("human override sempre vence" - a value changed since the candidate was
selected is never overwritten), one transaction per cell, readback
verification, and rollback that only restores a value still equal to what
was written. Candidates come exclusively from field_contract.resolve_product's
own AUTO_FILL_SAFE classification for CFOP/IPPT - no new fiscal rule.
14 new tests (agent/tests/test_cfop_ippt_auto_apply.py) prove: flag OFF means
the caller never reaches a write; only CHANGE+write_eligible CFOP/IPPT cells
become candidates; a human edit between decision and write blocks the write;
a second run over an already-applied cell writes zero; a technical failure on
one cell never stops the batch; rollback refuses when the value changed again.

Deliberately NOT wired into agent/scripts/run_agent_service.py::execute_job,
and the Hub-side authorization/audit plumbing (Installation.cfop_ippt_write_mode,
audit table, job-delivered authorization - the same pattern as
central/app/rtc_audit.py) does not exist yet. No currently-published Agent
behavior (1.3.8) changes with this commit - nothing imports this new module.
See docs/CFOP_IPPT_WRITE_CAPABILITY_V1.md for the acceptance roteiro (test
products only, never real ones) and what remains before this can ever be
activated for a real installation - deliberately left for review before any
further step, per this mission's explicit instruction not to publish it active.

Also: dossie_contador.md (internal + anonymized) updated with the Bloco B
finding that the ~9.5% CST=01 anomaly is confined to a single calendar month
(not the whole year), with no fiscal-dimension (NCM/CFOP/CSOSN/ICMS group)
explaining which items got it - consistent with a one-off technical event,
not a deliberate rule.

REAL_PRODUCT_FISCAL_WRITES=0 (no write path exists in this commit).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 10:12:39 -03:00

4.8 KiB

CFOP/IPPT write capability V1 — Missão 3 / Bloco C

Estado atual: núcleo implementado e testado, NÃO ligado, NÃO publicado

  • agent/src/gti_fiscal_agent/cfop_ippt_auto_apply.py — lógica pura (sem I/O de rede): write_gate, select_candidates (só células CHANGE+write_eligible=True de field_contract.resolve_product, restrito a CFOP/IPPT — nenhuma regra nova, reaproveita o motor já testado), apply_candidate (compare-before-write, stale-write guard = "human override vence", readback, uma transação por célula), apply_candidates (lote, uma falha nunca para o resto), rollback_one/rollback_records.
  • agent/tests/test_cfop_ippt_auto_apply.py — 14 testes, todos verdes: flag OFF nunca escreve; só células AUTO_FILL_SAFE viram candidatas; valor alterado por humano entre a decisão e a escrita aborta sem gravar (STALE_VALUE_CHANGED_SINCE_DECISION); segunda execução sobre a mesma célula já aplicada grava 0 (NO_WRITE_REQUIRED); readback divergente nunca retorna APPLIED; rollback só restaura se o valor atual ainda for o que foi escrito.
  • Nada disto está ligado ao execute_job do Agent, nem existe ainda o lado Hub (coluna Installation.cfop_ippt_write_mode, tabela de auditoria, entrega da autorização dentro do job - o mesmo padrão já usado pelo RTC, central/app/rtc_audit.py/installations.rtc_write_mode). Nenhum comportamento do Agent publicado (1.3.8) muda com este commit — nenhum código existente importa este módulo novo.

Por que parar aqui nesta passada

A mission pediu explicitamente para NÃO publicar isto como ativo sem revisão. Ligar de fato (migração + coluna + tabela de auditoria + endpoint + execute_job + testes de integração da ligação) é o próximo passo natural, mas só depois de:

  1. Você revisar este relatório e o Bloco C.1 (candidatas rebaixadas).
  2. Decidir se a exclusão manual das 9 células de evidência fraca (ver Bloco C.1) deve ser um mecanismo do capability em si (ex.: lista de exclusão por produto) ou uma melhoria futura na evidência do field_contract (contagem/proporção de C000032.TIPO=COMPOSICAO, hoje é só um in/not in binário no Agent, nunca uma taxa).

Roteiro de acceptance (produtos DE TESTE, nunca produtos reais) — a rodar quando a ligação existir

  1. Preparar: operador cria 2 produtos de teste no SGV de teste/sandbox (nunca em produção): um com CFOP em branco e papel de produto comprovável (ex.: TIPO=VENDA, evidência de revenda clara), outro com IPPT="T" mas uma entrada C000032.TIPO=COMPOSICAO clara e majoritária para o mesmo CODPRODUTO.
  2. Rodar REPROCESS_PRODUCTS em modo DRY_RUN (capability ligada, cfop_ippt_write_mode=DRY_RUN): confirmar que o job relata os 2 candidatos, sem nenhuma escrita (writes_attempted=0 no resultado do job).
  3. Ligar cfop_ippt_write_mode=ENABLED só para essa instalação de teste; rodar de novo: confirmar write_successes=2, os 2 valores corrigidos no Firebird, auditoria com old_value/ new_value/job_id para cada célula.
  4. Editar manualmente um dos 2 produtos no SGV para um TERCEIRO valor (nem o antigo nem o proposto) e disparar REPROCESS_PRODUCTS de novo sem terceira mudança de cadastro: como o valor já bate com o proposto ou já foi decidido, a resposta esperada é write_successes=0 (NO_WRITE_REQUIRED se já correto, ou nada a propor se o motor já vir o valor humano como ALREADY_CORRECT/válido).
  5. Critério de PASS: (i) flag OFF = 0 escritas em todos os passos; (ii) só CFOP/IPPT tocados, nunca outro campo; (iii) segunda execução idêntica = 0 escritas; (iv) edição humana entre a decisão e a escrita nunca é sobrescrita; (v) toda escrita aparece na auditoria com valor antigo, novo, job_id e timestamp; (vi) rollback de uma célula aplicada restaura o valor antigo só se ninguém mexeu de novo.

Só depois de um PASS completo nesse roteiro (produtos de teste) é que as 12 células reais do Agent 2 (Bloco C.1) devem ser consideradas para uma primeira aplicação real — e mesmo assim, só as que sustentam a evidência (ver rebaixamento no Bloco C.1), nunca o lote inteiro de uma vez.

Se/quando o Agent mudar de fato (fora desta passada)

Bump para 1.3.11 (release/VERSION, agent/pyproject.toml, agent/scripts/run_agent_service.py's default, agent/src/gti_fiscal_agent/preflight.py, todos juntos - mesma disciplina de test_agent_version_is_internally_coherent), build do installer (scripts/build_agent_package.py), validação em Windows Sandbox (scratch_sandbox/gti.wsb já existe de releases anteriores: instalar, upgrade in-place preservando installation_id/SQLite, confirmar cfop_ippt_write_mode chega DISABLED por padrão mesmo depois do upgrade). O upgrade na máquina real do Agent 2 continua sendo do operador (sem canal remoto).