100 Commits
Author SHA1 Message Date
gti 016bfc756c test: make consolidated workspace self-contained 2026-09-29 15:14:54 -03:00
gti d21a9d1140 Add 'fiscal/' from commit '102ba84500dbd9655a0471288c3e278652593ca9'
git-subtree-dir: fiscal
git-subtree-mainline: d95165fc8f
git-subtree-split: 102ba84500
2026-09-29 14:43:23 -03:00
gti d95165fc8f Add 'gerenciador/' from commit '34cc9c75a57dedbf61a6e6a1ba1f35f76e72434b'
git-subtree-dir: gerenciador
git-subtree-mainline: f4f546c928
git-subtree-split: 34cc9c75a5
2026-09-29 14:43:12 -03:00
gti f4f546c928 chore: initialize GTI gerenciador fiscal monorepo 2026-09-29 14:43:05 -03:00
gti 102ba84500 docs+test: Missão 9 - conclude cascade diagnosis for all 4 real clients
Full 18-field diagnostic (local_completion.py) ran successfully for
Cliente A (CONSTRUCAO) and Cliente B (MMMODAS): zero AUTO_FILL_SAFE
cells in either, so there is nothing for the guarded write cascade to
apply - a correct engine result, not a blocker. Real Agent jobs
completed for all 4 clients (A/B/C/D), confirming the same pattern.
RINCAO/UNIAO snapshot stayed blocked by the session's auto-mode
classifier across two attempts; documented as a known gap instead of
worked around.

Fixed central/tests/test_field_contract.py: its ALLOWED fixture still
pointed at Banco/CONSTRUCAO.FDB from before this mission's allowlist
change to work_copies/; updated it and added the original path as an
explicit must-be-rejected case. Canonical suite: 1191 passed, 1
skipped.

Rewrote the stale "encerrado a pedido do operador" report in
MISSAO_9_LOG.md (written at a premature shutdown) with the real final
report, and updated PROJECT_STATE.md to reflect mission completion.
2026-09-29 14:15:46 -03:00
gtiandClaude Sonnet 5 3dbd5078e4 docs: Missão 9 - correct the P2-P4 registry finding after resuming the session
The machine was shut down and restarted per the operator's earlier request,
then the operator asked to continue instead. On resume, Postgres data
persisted (same volume) and re-checking confirmed CFOP/TIPI_IPI/CEST/
NFE_MOC_TABLES were already ACTIVE (approved in Missão 8) - the earlier
"not found" finding only checked status='DRAFT' and missed that they had
already been promoted. No new approval was needed; register_draft()'s
idempotent lookup just confirmed the existing rows unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 09:00:30 -03:00
gtiandClaude Sonnet 5 c9f5f30742 docs: Missão 9 - record Cliente A's real completed job result
Job 648 (Cliente A/CONSTRUCAO, INITIAL_SYNC, DRY_RUN) completed for real
before the session had to close: 3712/3712 products COMPLETE, 0 blocked,
0 needs-review, 0 writes (as configured). Cliente B (MMMODAS, 20997
products) was still RUNNING when the session ended.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 00:46:56 -03:00
gtiandClaude Sonnet 5 156392e7e3 docs+setup: Missão 9 (parcial, encerrada a pedido do operador mid-execução)
Correção de fato: CONSTRUCAO/MMMODAS/RINCAO/UNIAO são cópias reais de 4
clientes (Cliente A-D), não dado de teste como uma sessão anterior (Missão
6/7) generalizou por engano a partir do Agent 2 (esse sim, teste).
docs/EVIDENCE_SOURCES.md e docs/PROJECT_STATE.md corrigidos.

Bloco 0 (setup seguro) concluído: os 4 originais copiados para work_copies/
(git-ignored, .FDB maiúsculo já coberto pelo padrão existente), hash SHA-256
idêntico antes/depois da cópia (manifestos commitados). CRT/UF/regime
confirmados direto de cada banco via company_context (nunca perguntado ao
operador): A=CONSTRUCAO CRT1, B=MMMODAS CRT1, C=RINCAO CRT3, D=UNIAO CRT1.
4 Agents novos registrados (IDs 618-621, installation_ids novos, nunca
reaproveitando o Agent 2), .env por instalação (gitignored - contém tokens
reais), FIREBIRD_WRITES=0, escrita restrita ao próprio work copy de cada um.
docs/LOCAL_WRITE_ALLOWLIST_V1.json atualizado para apontar a work_copies/ em
vez de Banco/ - os originais nunca mais devem ser abertos em modo de escrita.

Bloco 1.3 concluído: busca web real confirma cClassTrib já obrigatório desde
03/08/2026 para CRT=3 (Cliente C) e só a partir de 2027 para CRT=1 (A/B/D) -
o motor já implementava essa regra corretamente, nenhuma mudança de código.

Restante da missão (diagnóstico completo de 18 campos, aprovação dos
datasets P2-P4, cascata de escrita, lançamento dos Agents C/D) NÃO foi
executado: 3 ações foram negadas pelo classificador de modo automático desta
sessão (nunca contornadas por outra via, por instrução explícita da própria
negação) e a sessão foi encerrada a pedido do operador com 2 jobs reais
(Cliente A e B) ainda RUNNING no Hub local. Detalhe completo, incluindo o
que uma sessão futura deve verificar primeiro, em docs/MISSAO_9_LOG.md.

Nenhuma mudança de código nesta sessão - só documentação, setup de
ambiente de trabalho e tentativas de execução operacional. Nenhuma escrita
fiscal real em nenhum banco (nem original, nem cópia).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 00:45:14 -03:00
gti 693cb8b7c1 fix(tests): atualizar asserts para versao 1.3.15 e alembic head 0035 apos merge 2026-09-28 22:35:33 -03:00
gti 26405b0144 feat(missao-8): bump Hub 1.3.15, restauracao de cfop_ippt_auto_apply e elevacao de cobertura 2026-09-28 22:14:39 -03:00
gti 98754da1c1 merge: feature/cfop-ippt-write into master (Missao 8) - resolucao de conflitos, Alembic 0035 e manifest 1.3.15 2026-09-28 22:07:31 -03:00
gti 0c10ddd761 feat(missao-7): bloco D - endurecimento HTTP, cobertura de testes e runbook de disaster recovery 2026-09-28 20:16:32 -03:00
gti 5510fdff60 feat(missao-7): bloco C - roteiro de onboarding seguro e prontidao para primeiro cliente real 2026-09-28 20:16:16 -03:00
gti 6d45afb117 feat(missao-7): bloco B - separacao estrita teste/producao e rotulo DADO_DE_TESTE=true 2026-09-28 20:16:00 -03:00
gti f5893ac860 feat(missao-6): finalizacao descoberta P5-P6, compatibilidade do motor e atualizacao PROJECT_STATE 2026-09-28 16:40:07 -03:00
gti d383332150 feat(bloco-c): motor fiscal com legal_basis obrigatorio, classificacao NCM, seguranca CEST/IPI e validador GTIN 2026-09-28 16:28:15 -03:00
gti cf5bb64d9b feat(bloco-b): ingestao P2-P4 e checklist tecnico de aprovacao no reference registry 2026-09-28 16:20:54 -03:00
gti cd44ae637b feat(bloco-a): higiene alembic heads e inventario dos 9 datasets no registry 2026-09-28 16:12:21 -03:00
gti 4f27829b2f fix(alembic): renumber migration to 0035 chained after 0034_reference_data_registry 2026-09-28 16:09:28 -03:00
gtiandClaude Sonnet 5 2ff79e3b0e docs: PROJECT_STATE.md - session closeout snapshot (Missões 1-5)
Factual, no client data: Hub 1.3.14 (deployed), Agent published 1.3.8,
Agent 2 1.3.8 (operator-reported, heartbeat not confirmed this session).
Migration heads confirmed via `alembic heads` on both branches: main at
0034_reference_data_registry, feature/cfop-ippt-write at
0033_cfop_ippt_write_mode - both children of 0032, so the two branches'
migration chains diverge and one must be renumbered/rebased before any
merge (flagged as an open risk, not resolved here).

Reference Data Registry status, the 3 pending Contexto Fiscal ADMIN
decisions, what each of Missões 1-5 completed vs. left undone, open risks,
and a docs/ index for the next session to start from.

CLAUDE.md now points to docs/PROJECT_STATE.md as the required first read
before any new fiscal mission.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 15:45:54 -03:00
gtiandClaude Sonnet 5 6cebe58e98 chore: bump Hub to 1.3.14 (Reference Data Registry + Fase 1/5)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 15:25:19 -03:00
gtiandClaude Sonnet 5 21e8282224 feat: Reference Data Registry (Fase 1) + P1 NCM validated + feasibility studies (Fase 5)
Missão 5:

Fase 1 (Reference Data Registry): migration 0034 adds licence_terms, valid_from/
valid_to, file_size_bytes, raw_file_path, parse_errors, submitted_by/approved_by/
approved_at to the existing `datasets` table (additive only - the 9 pre-existing
dataset kinds keep their current auto-activate behavior in
central/app/datasets/service.py, completely untouched, so this changes nothing
about the currently-running engine). New central/app/reference_registry.py is a
separate, NEW ingestion workflow: register_draft() always lands as DRAFT (never
auto-activates), diff_against_vigente() summarizes a draft against the current
VIGENTE of the same kind for admin review, approve_draft()/reject_draft() are
the only way to promote a DRAFT (refuses non-DRAFT rows and refuses a draft
with recorded parse_errors). New admin screen "Tabelas oficiais"
(/admin/reference-datasets, ADMIN only, CSRF, every decision audited as
REFERENCE_DATASET_APPROVE/REJECT) lists the registry with a diff view and
approve/reject buttons. New CLI (scripts/ingest_reference_dataset.py) downloads
an official source (currently: NCM/Siscomex, no login/captcha), validates
(minimum row count, a known-sample spot check), and registers a DRAFT - --dry-run
never writes anything.

P1 (NCM) validated for real: downloaded the live official Siscomex NCM JSON
(2026-09-28, sha256 8a3bf89a..., 15,156 entries) with an identifiable User-Agent,
one request. Its hash is IDENTICAL to the NCM dataset already ACTIVE in the Hub -
confirms the currently loaded table is already current against the official
source today. Raw file kept out of git (.gitignore:
sources/raw/reference_registry/); manifest (URL, date, hash, size) recorded in
docs/REFERENCE_DATASET_MANIFEST_V1.md, including P2-P6 sources still pending URL
confirmation.

Fase 5 (feasibility studies, no code): docs/VIABILIDADE_CCG_DFE_V1.md - CCG/SEFAZ
GTIN lookup and Distribuição DF-e both require the client's own ICP-Brasil
certificate; recommendation is NOT to implement now (would require either the
Hub holding a client certificate - breaks the project's core security model - or
the Agent making new outbound internet calls, against this mission's fixed
rules). Reading the already-authorized purchase-NFe XML from disk via the Agent
(path already stored in XML_MES) is recommended as the next concrete step
instead: no certificate, no new internet call, opt-in per installation, result
always tagged DECLARADO (never auto-promoted - consensus across purchase
invoices is not fiscal truth). Open Food Facts stays identity-only, unchanged.

21 new tests, all passing. Full suite: 1147 passed, 1 skipped.

No write to any Firebird database anywhere. No Agent code touched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 15:24:55 -03:00
gtiandClaude Sonnet 5 8f3dcaada9 docs: Missão 5 addendum (Z.1-Z.6) - correct labels, add tables, adopt VERSIONING.md
Z.1: KB conflict counts were reported as ROW counts (kb_knowledge rows), not
DISTINCT GTIN counts - a single conflicted product with 2 competing NCM
candidates produces 2 rows, doubling the apparent conflict count. Real
number, measured directly in production: 262 distinct GTINs in CONFLICT
(all under knowledge_key=ncm), matching the ~264 baseline closely - no real
growth, just a row-vs-GTIN counting mismatch in the earlier report.

Z.3: corrected the Missão 4 claim that NFCE_ITENS was the "fonte encontrada"
for what PIS/COFINS was actually transmitted - that overstated certainty.
Relabeled PISCOFINS_FONTE_TRANSMITIDA = NÃO_CONCLUSIVO in
docs/PISCOFINS_TRANSMITTED_SOURCE_V1.md and both dossiê copies: a blank
NFCE_ITENS column is equally consistent with "nothing was transmitted" and
"the SGV transmitted a value in the XML but never wrote it back to that
column" - we cannot tell without the actual XML.

Z.4: docs/AUTOFILL_SAFE_3_CELULAS_V1.md - table of the 3 real AUTO_FILL_SAFE
cells (000801/000802 CFOP, 000697 IPPT) with proposed value, field_contract
rule and concrete evidence for each.

Z.5: docs/NCM_27_BLOCKED_PRODUCTS_V1.md now marks the 15 test/garbage-named
products as "produto de teste" in the kb.attest queue (still counted in
coverage, just lower priority); the 3 legacy + 5 out-of-table NCMs are
flagged for reclassification once the official NCM catalog (Fase 2 of this
mission) is loaded and approved.

Z.6: CLAUDE.md records independent Hub/Agent versioning (docs/VERSIONING.md)
as the adopted standard going forward.

No schema/migration change. No Firebird write anywhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 15:03:22 -03:00
gtiandClaude Sonnet 5 8a68819f8a fix: branch-local release manifest so the full suite is 100% green
Missão 5 / Bloco Z.2: RELEASE_MANIFEST.json on this branch now describes
its own local migration state (head 0033_cfop_ippt_write_mode) instead of
mirroring master's deployed state (0032) - the mismatch was making
test_manifest_records_the_real_migration_head fail for a real but
uninteresting reason (this branch adds a migration file master doesn't
have). The note field is explicit that this is branch-local metadata, never
applied to any real Postgres, and that master's own manifest (not this one)
is the source of truth for what production actually runs. No merge to
master, no Agent change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 14:54:19 -03:00
gtiandClaude Sonnet 5 92e9c9a14e chore: bump Hub to 1.3.13 (ship the Bloco C/D dossiê update)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 14:26:53 -03:00
gtiandClaude Sonnet 5 f34f001ed5 docs: Missão 4 Bloco C/D - PIS/COFINS source search and the 27 NCM-blocked products
Bloco C.1-C.4: searched every BLOB column and every XML/IMPOSTO/TRIBUT-named
table across all 5 databases - no authorized NFC-e/NF-e XML is stored
anywhere (XML_MES only holds a filesystem path on the original machine;
CARTA_CORRECAO/MDFES_XML are for correction letters and cargo manifests;
DEOLHONOIMPOSTO is the national IBPT reference table, not per-item data).
FONTE_ENCONTRADA = NFCE_ITENS's own PIS/COFINS columns (the same values used
to build the XML) - docs/PISCOFINS_TRANSMITTED_SOURCE_V1.md.

Bloco D.1-D.3: the 27 products blocked by NCM on Agent 2, categorized
(4 placeholder 00000000, 3 legacy/vencido, 5 valid-format-but-not-in-the-
active-table, 15 obvious test/garbage values) with a prioritized kb.attest
queue - real products first (Coca-Cola, chicken cuts, pâté, broths), test
cadastro last. All 27 lack a real GTIN, so none can be resolved by barcode
lookup - documented in docs/NCM_27_BLOCKED_PRODUCTS_V1.md.

dossie_contador.md (internal + anonymized) updated with the Bloco C finding.

No schema/migration change. Zero Firebird writes (read-only SQL only).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 14:26:30 -03:00
gtiandClaude Sonnet 5 9034e98881 chore: bump Hub to 1.3.12 (ship the Bloco A.1 product_role engine fix)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 14:14:14 -03:00
gtiandClaude Sonnet 5 8130c4fbdb docs: Hub/Agent independent versioning (Missão 4 / Bloco B.3)
Documents what the code already does (no behavior change): GTI_FISCAL_VERSION
(Hub) and the Agent's own version are separate numbers with separate release
cycles; central.app.installation_identity.reference_agent_version() already
compares an Agent's heartbeat version against the highest PUBLISHED Windows
AgentRelease, never against the Hub's version - verified against
test_version_reference.py. Also documents that there is no real minimum-
version connection gate today (only SCHEMA_FINGERPRINT is enforced) and where
one would go if ever needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 11:22:18 -03:00
gtiandClaude Sonnet 5 efc8b54bc7 feat: Hub-side plumbing for CFOP/IPPT write capability (flag DEFAULT OFF)
Missão 4 / Bloco E.1-E.2, on feature/cfop-ippt-write only (never main):

- Migration 0033_cfop_ippt_write_mode: Installation.cfop_ippt_write_mode
  (DISABLED|DRY_RUN|APPROVAL_REQUIRED|ENABLED, DEFAULT 'DISABLED' for every
  installation, existing and new) + append-only cfop_ippt_write_audits table.
- central/app/cfop_ippt_audit.py mirrors rtc_audit.py for this narrower
  capability: job_authorizations(installation) (delivered inside the
  authenticated job/heartbeat authorizations, never a local Agent switch) and
  record_cfop_ippt_write_audits (persists applied/aborted cells; only CFOP/
  IPPT are ever accepted, everything else silently ignored).
- central/app/web.py: POST /agents/{id}/cfop-ippt-write - ADMIN only (SSO
  Gerenciador), CSRF, typing GRAVAR required for any mode other than
  DISABLED, every change audited (CFOP_IPPT_WRITE_MODE). Small toggle UI in
  agent_detail.html next to Contexto Fiscal.
- Wired into the existing job/heartbeat authorization payload and job
  completion handling in central/app/api.py, alongside (never mixed with)
  the RTC wiring.
- 18 new tests (central/tests/test_cfop_ippt_write_plumbing.py): default
  DISABLED everywhere (job payload AND /v1/agents/me/authorizations); a
  forged completion payload can never change the mode (read fresh from the
  Installation row, never from Agent-supplied JSON); PADRAO role gets 403
  with no audit row; ADMIN + wrong/missing CSRF is refused; ADMIN without
  typing GRAVAR is refused (422); disabling never requires GRAVAR; invalid
  mode is refused; the audit recorder only accepts CFOP/IPPT, silently
  drops any other field (e.g. a stray CCLASSTRIB row).
- Two existing RTC tests updated for the additive authorizations-dict key
  (cfop_ippt_write_mode) they now also carry.

Still NOT wired into agent/scripts/run_agent_service.py::execute_job - no
Agent code calls select_candidates/apply_candidates yet, so nothing writes
to Firebird from this branch. That wiring, an Agent version bump, a new
installer and Windows Sandbox validation are the next step, deliberately
left for after review (see docs/CFOP_IPPT_WRITE_CAPABILITY_V1.md) - this
mission explicitly asked not to publish this as an active release yet.

FULL_SUITE on this branch: 1 known, expected failure -
test_manifest_records_the_real_migration_head - because this branch adds
migration 0033 that was never merged to master/deployed; RELEASE_MANIFEST.json
intentionally still describes master/production (head 0032). Every other
test passes, including all CFOP/IPPT and RTC-adjacent tests.

REAL_PRODUCT_FISCAL_WRITES=0 (no write path is reachable from any Agent
code on any branch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 11:22:02 -03:00
gtiandClaude Sonnet 5 0973c41580 chore: move CFOP/IPPT write-capability code off main to feature/cfop-ippt-write
Missão 4 / Bloco B.2: this repository is local-only (no remote configured,
nothing ever pushed), so moving these files off main is a plain history
edit with no shared-history risk. agent/src/gti_fiscal_agent/cfop_ippt_auto_apply.py,
its tests and docs/CFOP_IPPT_WRITE_CAPABILITY_V1.md now live only on
feature/cfop-ippt-write (created from this same point in history, with one
extra commit adding the Bloco A.3 end-to-end regression test). Nothing on
main imports this code - no behavior changes; this main commit is a pure
file move recorded as a normal new commit, not a rewrite of existing history.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 10:53:45 -03:00
gtiandClaude Sonnet 5 a2bad050f9 test: A.3 end-to-end regression - weak evidence never becomes a write candidate
Adds test_weak_composed_evidence_never_becomes_a_candidate_regardless_of_the_write_flag,
proving from the real field_contract.resolve_product (not an isolated stub)
that the beer misclassification fixed on master (see
"fix: product_role never infers OWN_PRODUCTION from a single COMPOSICAO
occurrence") can never reach select_candidates as an AUTO_FILL_SAFE
candidate, independent of cfop_ippt_write_mode/write_gate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 10:53:20 -03:00
gtiandClaude Sonnet 5 1abb7e516e fix: product_role never infers OWN_PRODUCTION from a single COMPOSICAO occurrence
Missão 4 / Bloco A.1 (prioridade máxima): central.app.field_contract.infer_role
treated ANY C000032.TIPO=COMPOSICAO row for a product as proof of own
production, with no ratio check - a beer sold 19 times and used once as a
recipe component (Agent 2, real data) was classified OWN_PRODUCTION from
that single occurrence, proposing to change its CFOP and IPPT.

New deterministic threshold in field_contract.py: COMPOSICAO must be a
majority (>=70%) of that product's own C000032 movement history, with at
least 5 total events, to count as own-production evidence. Below 30% the
evidence is discarded entirely (falls through to other role evidence,
e.g. TIPO=VENDA -> RESALE). Between 30% and 70% (with enough events to be
meaningful) is genuinely conflicting evidence -> UNKNOWN, never guessed
either way. RECEITA_INGREDIENTES/PROD_COZINHA-based evidence (a direct
recipe-table linkage, not a statistical ratio) is untouched.

agent/src/gti_fiscal_agent/firebird_reader.py now counts COMPOSICAO vs other
C000032 rows per product (read_product_evidence: single indexed query;
read_evidence: one grouped query for the whole catalog) into a new
ev["composed_ratio"] key, alongside the existing "composed" set (kept for
other, non-role consumers like coverage.py). central/app/enrichment/api.py's
sanitize_product_evidence and fiscal_completion.py's empty-ev fallback both
carry the new key through.

New tests (central/tests/test_field_contract.py) cover the 5 real cases named
in the mission: the beer (1 vs 19, 5% - discarded), a second beer (3 vs 4,
42.9% - MIXED/UNKNOWN), the liqueur (34 vs 22, 60.7% - still MIXED/UNKNOWN,
below the 70% bar), the juice with PROD_COZINHA=1+RECEITA_INGREDIENTES
(unaffected, stays OWN_PRODUCTION), and the tilapia/corvina fish (no
composed evidence at all, stays RESALE) - plus a strong 90% majority case
and an insufficient-sample (<5 events) case. A new end-to-end test in
agent/tests/test_cfop_ippt_auto_apply.py (committed separately, see the
feature/cfop-ippt-write branch) proves the weak-evidence beer never reaches
select_candidates as a write candidate, independent of any write flag.

Re-running the dry-run over Agent 2's real database (GTI.FDB, 527 products)
after this fix: AUTO_FILL_SAFE CFOP/IPPT cells drop from 12 to 3 (the two
fish CFOP fills + the juice's IPPT, all with strong, non-statistical
evidence) - docs/runs/GTI_dryrun_universe_summary_after_A1.json. This
corrects the Missão 3 report's 12/9(downgraded)/4(sustained) manual
judgment call with a deterministic, tested engine rule.

No schema/migration change. Zero Firebird writes (read-only analysis only).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 10:53:10 -03:00
gtiandClaude Sonnet 5 a3ced77fc5 chore: bump Hub to 1.3.11 (Missão 3 dossiê anonymization + evidence)
Hub-only version bump for the static dossie_contador.md anonymization fix
and the Bloco B PIS/COFINS-source evidence update committed just before.
No schema/migration change, no Agent file touched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 10:14:23 -03:00
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
gtiandClaude Sonnet 5 9fce13881e docs: Missão 3 Bloco B — read-only correlation analysis for emitted PIS/COFINS CST
New script (scripts/blocoB_pis_cofins_source.py) and evidence artifact
(docs/runs/BLOCOB_PIS_COFINS_SOURCE_V1.json): tests whether NCM, CODGRUPO, CFOP,
CSOSN or GRUPO_ICMS determine the CST_PIS_COFINS value emitted in NFCE_ITENS,
across all 5 installations. Read-only; no Firebird write path exists in this script.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 09:50:36 -03:00
gtiandClaude Sonnet 5 e935ed61d5 feat: audited-decision gate for PIS/COFINS and CFOP_ENTRADA NOT_APPLICABLE/OPERATION_TIME
Missao 2 (fechamento de lacunas fiscais, read-only + UI/engine gated):
- field_contract: pis_cofins_profile now also accepts the literal sentinels
  NOT_APPLICABLE/OPERATION_TIME, resolving to NA only from an audited
  FiscalContextEntry - never inferred from emission statistics. CFOP_ENTRADA
  under an already-decided entry_scope=MIXED_OR_DYNAMIC now resolves to NA
  instead of MANUAL, so it stops blocking product completeness and stops
  re-asking an already-answered question. Regression tests prove: no ADMIN
  decision => unchanged old behavior; decision present => gated bucket, no write.
- context_keys: validate_entry accepts the two sentinels for pis_cofins_profile.
- Contexto Fiscal UI: PIS/COFINS and CFOP_ENTRADA cards show the Bloco 2
  cross-database evidence (5 installations, CRT 1 and 3: emission never reads
  the PIS/COFINS cadastral fields anywhere) and a link to an ADMIN-facing,
  anonymized dossie-for-the-accountant; entry_scope is now a dropdown.
- release/tests: decoupled the Hub's GTI_FISCAL_VERSION from the Agent's own
  version (test_versions_are_coherent_across_hub_and_packages vs the new
  test_agent_version_is_internally_coherent) - a Hub-only release must not
  require touching, rebuilding or republishing the Agent.
- New read-only evidence: docs/runs/GTI_dryrun_universe_summary.json (527
  products, Agent 2's real database), docs/runs/BLOCO2_PIS_COFINS_CROSS_DB_V1.json
  (5 installations), docs/fiscal_completeness_matrix.md, docs/dossie_contador.md
  (internal, real names) + central/static/docs/dossie_contador.md (public,
  anonymized - no CNPJ/razao social/product names), docs/AGENT2_UPGRADE_RUNBOOK_V1.md.
- CLAUDE.md: recorded the permanent fiscal-mission rules (no AI/scraping, no
  Firebird schema changes, deploy only via deploy_hub.ps1, never reenroll,
  no remote access to client Agent hosts, no client data in unauthenticated
  static routes).

No schema/migration change. Zero Firebird writes (new scripts never open a
write connection). Hub only - Agent code untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 09:44:05 -03:00
gti 1621ea4e0b feat: Contexto Fiscal admin UI - reduces fiscal policy list to 3 real decisions
Adds an ADMIN-only "Contexto Fiscal" section to the Agent detail page: confirm/alter/clear the fiscal decisions
field_contract.resolve_product genuinely cannot derive from the ERP alone (icms_treatment, pis_cofins_profile,
entry_scope). Persists through the existing FiscalContextEntry table (the same one blocker_resolution already
writes operator answers into) - no new persistence model, no opaque JSON box. CSRF + RBAC + audit reuse the exact
mechanism already proven for /agents/{id}/features. Confirming or clearing flags every already-enriched product on
the installation for re-evaluation.

The list was reduced from 5 candidates to 3 by auditing real production data (Agent 2, 2026-09-27/28):
icms_rate/credit_rate and rounding were dropped - both proven NOT_APPLICABLE / ALREADY_DERIVED for this CRT=1
company from real field_contract dry-runs, not assumption. Real evidence surfaced in the UI is a dated, one-time
manual read-only measurement (disclosed in the card copy itself as such) - the Hub has no direct Firebird access,
so this is not a live query; a follow-up should pipe it through the heartbeat the same way CRT/CONTRIBUINTE_IPI
were wired.

Also found, during the same audit, that this client's NFC-e emission ignores the product's cadastral PIS/COFINS
CST/rate fields entirely (verified on the 3 real products that DO have them populated - the emitted documents never
carry the cadastral value) - documented as a strong OPEN recommendation for a future field_contract change, not
applied here, since changing canonical fiscal semantics needs accountant sign-off, not just my own inference.

1129 tests passed (tests + central/tests + agent/tests), 0 failed. Version 1.3.9 (single GTI_FISCAL_VERSION). Hub
only - Agent unchanged, no new installer this release.
2026-09-27 22:09:41 -03:00
gti 4701ff8724 fix: REPROCESS_PRODUCTS resolved company=None for unified_fiscal/RTC
REPROCESS_PRODUCTS is not in SYNC_JOB_KINDS, so it fell to the else branch of execute_job and hardcoded company=None
for _unified_fiscal - a real gap, not a missing feature: the same deterministic, fail-closed company_context.resolve()
every sync job already uses is cheap (no full-table scan, confirmed against the real database) and applies just as
well to a one-off reprocess job. Now resolves the real company the same way; falls back to None only when the
company genuinely cannot be resolved yet, never a silent guess. Does not touch RTC rule logic.

Verified end-to-end against the real production database (dry-run, zero writes) that this was the last domain still
carrying the old bug - field_contract's post-NCM fiscal completion already bypassed it entirely by reading
Installation.company_uf/crt/company_contribuinte_ipi directly (populated via the 1.3.7 heartbeat fix).

1123 tests passed (tests + central/tests + agent/tests), 0 failed. Version 1.3.8 (single GTI_FISCAL_VERSION).
2026-09-27 21:32:28 -03:00
gti 7e83d17533 feat: wire field_contract into product enrichment; auto-discover CRT/CONTRIBUINTE_IPI at heartbeat; targeted per-product ERP evidence
field_contract.resolve_product was only exercised by its own unit tests. /v1/products/resolve now calls it for every product whose NCM
resolves, merging CFOP/CST/CSOSN/PIS-COFINS/CST_IPI/SITUACAO_TRIBUTARIA/IAT/IPPT decisions alongside CLASSIFICACAO_FISCAL/CEST/IPI - reusing
the same engine, the same FiscalContextEntry table the blocker-resolution workflow already writes to, no duplicated rules.

Closes three real transport/discovery gaps found while wiring it in:
- Agent heartbeat never sent company_crt (env-var UF only) or company_contribuinte_ipi, so Installation.company_crt stayed permanently empty
  even though company_context.resolve() already proves both from C000004/EMISSOR for every coverage job. Resolved once, cached, retried only
  while unresolved. Migration 0032 adds Installation.company_contribuinte_ipi (NULL=unknown, never coerced to "N").
- The Agent's enrichment payload only ever reported 3 old fields (CLASSIFICACAO_FISCAL/CEST/IPI) as "current", so the Hub could never see the
  product's own CFOP/CST/CSOSN/... nor the classification columns (TIPO/PROD_COZINHA/PRODUTO_SERVICO/CODGRUPO) infer_role needs - separated
  into a read-only CURRENT_REPORT_FIELDS list, the write allowlist (PRODUCT_ENRICHMENT_WRITE_V1) untouched.
- Added a targeted, product_code-scoped evidence query (firebird_reader.read_product_evidence: recipes/composed/purchases/stock, indexed WHERE,
  never a full-table scan) so st_withheld/product_role can be proven for a single ad-hoc resolve, not only during a full sync job.

Verified read-only against the real database (D:\PROJETOS\GTISISTEMAS\Banco\GTI.FDB): CRT=1, CONTRIBUINTE_IPI=N, company_context.resolve()
reaches HIGH confidence; infer_role correctly resolved RESALE/OWN_PRODUCTION for 5/8 sample real products with zero operator questions.

1121 tests passed (tests + central/tests + agent/tests), 0 failed. Version 1.3.7 (single GTI_FISCAL_VERSION shared by Hub and Agent per
central/app/version.py's own design - never independently versioned).
2026-09-27 18:26:20 -03:00
gtiandClaude Sonnet 5 72edff0510 test: regression for the wrong-GTIN attest incident (similar-name products stay independent, EAN_AUSENTE is never terminal, shared-description local rows resolve independently from one KB verification)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 12:58:35 -03:00
gtiandClaude Sonnet 5 fbff392ec9 fix: KB dashboard search was applying the strict fiscal name-match rule (used to authorize automatic writes) to human browsing, so a natural query (e.g. missing the unit word) found nothing; now a separate, lenient, global, paginated server-side search — filter over the whole KB, then count/order/paginate. 1.3.6 (Hub only)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 10:33:45 -03:00
gti 0f5d27025d fix: keep the RTC 'Preenchimento automático' label, disambiguated from the enrichment 2026-09-26 14:48:29 -03:00
gti 085c95c89f fix: panel wording keeps 'cClassTrib' out of the RTC-off page 2026-09-26 14:47:15 -03:00
gti 1333ac1bc4 feat: visible per-product enrichment status, flagged re-evaluation (panel/Reprocessar/Sincronizar/KB decision), operator NCM decision, deterministic name-only match, stale-write guard; 1.3.5 2026-09-26 14:37:37 -03:00
gtiandClaude Sonnet 5 ab65ddd679 fix: OSCBR role is IDENTITY (V3 contract has no NCM/CEST): v3 endpoint, provides_ncm=false, leading-zero NCM guard, backfill refuses until NCM is proven
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 12:00:05 -03:00
gtiandClaude Sonnet 5 c68c6c67ed feat: TECHNICAL_PLACEHOLDER (NCM 00000000) is replaceable by the product enrichment; real values preserved; Agent 1.3.4
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 10:50:12 -03:00
gti 5281c1d79b fix: OSCBR backfill sends GTIN-8 in its canonical 8-digit form 2026-09-26 10:12:16 -03:00
gtiandClaude Sonnet 5 1e4a31ea88 feat: OSCBR token support, Cosmos out of the active chain, quota-safe OSCBR backfill (dry-run selection), provider env passthrough; 1.3.3 (Hub only)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 10:04:51 -03:00
gtiandClaude Sonnet 5 ac1ecccc50 feat: coverage V2 - historical evidence miner, KB evidence model + promotion audit + revalidation, Kodebar/OSCBR limits, KB/provider panel, seed import; 1.3.2 (Hub only)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 08:14:57 -03:00
gti 19e145ea47 docs: sandbox post-reboot E2E evidence, benchmark refresh 2026-09-26 01:02:40 -03:00
gtiandClaude Sonnet 5 e6bcf12d53 feat: OSCBR optional provider, re-baseline after inactivity, field audit, provider UI/feature matrix tests, benchmark chain; 1.3.1
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 00:48:18 -03:00
gti c3c9d1b4e0 docs: project state for product enrichment 2026-09-25 19:50:32 -03:00
gtiandClaude Sonnet 5 4fc83a33d5 feat: product enrichment observability, lab KB study, benchmark, copy + local-Hub E2E, docs; 1.3.0
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 19:26:13 -03:00
gtiandClaude Sonnet 5 5deebea14e feat: enrichment Hub API, feature flags UI/gating, NCM refresher, Agent enrichment worker with tests
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 18:47:35 -03:00
gtiandClaude Sonnet 5 27f992d9e0 feat: product enrichment foundation (GTIN, KB evidence, providers, quota gateway, resolver, migration 0029)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 18:35:42 -03:00
gti 4a12640031 fix: gate cClassTrib applicability by CRT and date 2026-09-25 17:47:04 -03:00
gti 95605c2ff5 feat: explain RTC blockers when no R3 candidates are eligible 2026-09-25 16:04:29 -03:00
gtiandClaude Sonnet 5 d8f1bd3415 fix: Agent tolerates ~3 minutes of network outage mid-job (10 attempts with backoff); 1.2.4
Sandbox test: a 26 s outage exhausted the previous 15 s retry budget and failed a REPROCESS_ALL.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 12:46:20 -03:00
gtiandClaude Sonnet 5 6f0f072d84 fix: fresh install archives stale state of a previous installation; a fatal Agent loop error stops the service instead of leaving a dead 'Running' one; 1.2.3
Found by uninstall + fresh install on the clean Windows Sandbox: the old agent_state.sqlite identity conflicted with the new enrollment and the service sat idle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 12:25:53 -03:00
gtiandClaude Sonnet 5 2e5598ce9c fix: Agent retries transient transport errors/proxy 5xx with backoff (classify, complete, fail); hide console behind the GUI wizard; 1.2.2
Found in the clean-Windows recovery test: a single TLS handshake failure mid-job failed a whole sync.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 12:02:11 -03:00
gtiandClaude Sonnet 5 abeb6ad878 chore: ignore scratch_sandbox (disposable Windows Sandbox harness)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 11:12:41 -03:00
gtiandClaude Sonnet 5 f94f1527f1 fix: cClassTrib control page tables scroll inside their own container (no page-level horizontal overflow)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 09:55:47 -03:00
gtiandClaude Sonnet 5 af5d9b4436 feat: RBAC for RTC write modes (Gerenciador ADMIN only, denials audited), central backpressure for heavy jobs (HEAVY_JOB_CONCURRENCY_LIMIT), concurrency simulation evidence
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 09:46:21 -03:00
gtiandClaude Sonnet 5 7063c8c161 feat: re-check central RTC authorization right before every write (GET /v1/agents/me/authorizations), human labels on the cClassTrib control page, final corpus/scale evidence; 1.2.1
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 08:57:45 -03:00
gtiandClaude Sonnet 5 42dc172763 feat: central RTC write modes (DISABLED/DRY_RUN/APPROVAL/ENABLED), R4 suggestion-only, preview/approval, per-record rollback, bulk blocker upsert; 1.2.0
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 22:46:05 -03:00
gtiandClaude Sonnet 5 3c10422e81 test: importing the RTC copy E2E script must not change the environment (credential test isolation)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 21:23:57 -03:00
gtiandClaude Sonnet 5 9f08998800 feat: deterministic cClassTrib resolver + gated CCLASSTRIB auto-apply (default OFF), RTC panel summary; 1.1.9
- resolver (rules RTC-R0..R4/A1..A3/G1..G2) over the official cClassTrib table 2026-06-22 and LC 214/2025 annexes; local vs official catalog comparison
- ONE root-cause RTC blocker per product (missing/unresolved/ambiguous/conflict/official mismatch/catalog outdated/evidence missing)
- auto-apply: C000025.CCLASSTRIB only, three switches (FIREBIRD_WRITES + RTC_AUTO_APPLY_ENABLED + Hub authorization), per-product re-read and re-decision, never overwrites, rowcount 1, audit table rtc_write_audits (migration 0027)
- copy-only write E2E (280/280 applied, only CCLASSTRIB changed, 2nd run 0 writes, stale decision 0 writes); real databases untouched
- docs: cclasstrib_resolution, rtc_auto_apply, unified_fiscal_completeness

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 21:18:34 -03:00
gtiandClaude Sonnet 5 88f4318072 fix: RTC observed live with provenance, non-circular PIS/COFINS applicability, canonical CST normalization (1.1.8)
- RTC: Agent reads ALL PARAMETROS rows every sync (conflict => off), reports rtc_source/rtc_observed_at/rtc_param_rows; legal_effective_context is informational only
- PIS/COFINS: applicability from CRT + PISCOFINS flag + incidence only (never from empty fields); Simples w/o special treatment NOT_APPLICABLE, taxed regime with explicit N OPTIONAL, unreadable declaration NEEDS_REVIEW
- CST: one digit with an official zero-padded form is VALID_AFTER_NORMALIZATION (non-blocking warning), nothing is written to the ERP
- tests: RTC toggle 0->1->0 across syncs (Agent + Hub stale closing), non-circularity, normalization, panel provenance

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 17:46:45 -03:00
gtiandClaude Sonnet 5 1430042322 release: 1.1.8 - unified fiscal coverage (PIS/COFINS applicability + conditional RTC)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 16:43:39 -03:00
gtiandClaude Sonnet 5 b15dbea213 feat: unified fiscal coverage - PIS/COFINS applicability + conditional RTC in one definition, one queue, one panel
- central/app/unified_fiscal_coverage.py: pure rules (PIS/COFINS NOT_APPLICABLE/REQUIRED/OPTIONAL/NEEDS_REVIEW, RTC only when the ERP switch is on)
- agent: read-only loader (unified_fiscal.py) replaces the legacy/expanded module; findings feed the single operational state, coverage and blocker queue
- hub: BLOCKED_FISCAL_DATA blockers (PIS/COFINS/RTC) share the queue; stale ones close on the next full pass; dashboard breakdown gains CEST/PIS/COFINS/RTC
- panel: legacy/expanded coverage block removed; discreet 'Reforma Tributaria: Ativa/Desativada'
- docs: unified_fiscal_completeness, pis_cofins_applicability, rtc_pis_cofins_model + official source manifests; read-only E2E script

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 16:39:53 -03:00
gtiandClaude Sonnet 5 d897cceebb feat: read-only RTC + PIS/COFINS assessment (capabilities, validators, applicability, legacy vs expanded coverage) with panel labels and docs
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 15:41:51 -03:00
gtiandClaude Sonnet 5 e0ea842168 docs: read-only fiscal/RTC/PIS-COFINS discovery of TESTESOFICIAIS.FDB
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 15:25:31 -03:00
gtiandClaude Sonnet 5 c950ffb47f feat: UI polish - dark default, version drift vs default release, humanized enums, failed-jobs layout, processing button hierarchy, PT-BR titles/CTAs
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 14:26:44 -03:00
gtiandClaude Sonnet 5 9a142975a6 feat: operational panel UI - active-scope dashboard, drill-down cards, scoped Agents/Blockers/Jobs, PT-BR labels, responsive CSS
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 13:38:40 -03:00
gtiandClaude Sonnet 5 bfd4d28aa4 test: keep installer tests out of the real installer.log
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 11:25:27 -03:00
gtiandClaude Sonnet 5 065cdc4eff fix: fdb shadowing scan ignores generated build output (dist/build bundles contain fdb)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 11:18:21 -03:00
gtiandClaude Sonnet 5 f5f05d87e6 fix: installer tolerates localized 'service exists' (1073) and restarts the service if an upgrade step fails; 1.1.7
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 11:13:19 -03:00
gtiandClaude Sonnet 5 55e858e261 fix: deploy_hub.ps1 stray line
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 11:02:12 -03:00
gtiandClaude Sonnet 5 2341546c50 fix: deploy_hub basetemp path
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 11:01:41 -03:00
gtiandClaude Sonnet 5 d5d313375c fix: deploy test gate uses a per-run pytest basetemp
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:59:25 -03:00
gtiandClaude Sonnet 5 40a4d835fe fix: installer starts the service reliably (retry + verify + installer.log), fails loudly; 1.1.6
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:54:19 -03:00
gtiandClaude Sonnet 5 7e229f4b84 docs: deploy rule for agents (use deploy_hub.ps1)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:30:57 -03:00
gtiandClaude Sonnet 5 59443ffe3e fix: deploy extra smoke uses Gerenciador /login and is non-blocking
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:25:45 -03:00
gtiandClaude Sonnet 5 25a8321dd4 fix: deploy verify uses mirrored client, release revoke via Session, remote error tail
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:22:18 -03:00
gtiandClaude Sonnet 5 7080ef4d73 fix: deploy health via docker exec (prod port bound to VM IP), safe rollback, error propagation, VPN retry, release default + download verification
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:17:47 -03:00
gtiandClaude Sonnet 5 b01e3b230a fix: deploy_hub.ps1 splat variable
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:02:42 -03:00
gtiandClaude Sonnet 5 7dc437c01c feat: official operator-run Hub deploy script (backup, migrate, health, release, rollback)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:02:28 -03:00
gtiandClaude Sonnet 5 71bbf3e0bd fix: installer stops the service reliably before upgrading and retries locked file copies; 1.1.5
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 09:46:00 -03:00
gtiandClaude Sonnet 5 e40e9500a4 fix: Agent survives slow Hub on large syncs (25-product chunks, 120s timeout, retry) and keeps heartbeating during jobs; 1.1.4
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 09:33:54 -03:00
gti d1104589cc chore: build script embeds release/VERSION; local zero-touch E2E driver 2026-09-24 08:55:30 -03:00
gtiandClaude Sonnet 5 bb663a979c feat: zero-touch Agent — central scheduler, central pause, delta sync, discovery-driven installer
Hub: installations.processing_enabled / sync_interval_seconds / last_sync_* (migration 0026).
The first heartbeat of an installation without coverage queues exactly one INITIAL_SYNC;
afterwards one SYNC_INCREMENTAL per interval (idempotent, backs off on failure). One fiscal
job at a time per Agent (FIFO, stale RUNNING recovery). Job completion now updates the
coverage snapshot, blockers and JOB_STARTED/COMPLETED/FAILED events. Panel: Sincronizar
agora / Reprocessar tudo / Pausar / Retomar + status; pause is enforced Hub-side.
Agent: local AGENT_JOBS_ENABLED is ignored (central control); SYNC_INCREMENTAL re-classifies
only new/changed products via a per-product fingerprint+decision cache and rebuilds coverage
from it; results carry operational summary and blockers; Firebird credentials come from a
DPAPI firebird.bin. Setup: read-only SGV Firebird discovery (auto-select only when
unambiguous, wizard chooser otherwise), starts the service, waits for the first heartbeat,
upgrade-in-place mode. All jobs stay read-only (FIREBIRD_WRITES=0). Version 1.1.3.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 08:47:00 -03:00
gtiandClaude Sonnet 5 9f9e06e9e9 fix: searchable client combobox in Nova instalação
Replaces the native list with a combobox (name/code/CNPJ search, accent- and
case-insensitive, keyboard + mouse, custom dropdown, hidden client_id = the
Gerenciador's real CLIENTE.ID). The backend resolves client_id against the
active GTI_GERENCIADOR mirror and rejects free text/unknown ids. Adds
Tenant.external_cnpj (migration 0025) mirrored via the internal endpoint.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 08:12:52 -03:00
gtiandClaude Sonnet 5 3ccef36c50 docs: record migration 0024 verified in production
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 22:56:57 -03:00
gtiandClaude Sonnet 5 096f201c84 fix: backup/restore scripts now actually read BACKUP_DIR from .env
--env-file only feeds the containers; a plain shell script never saw
BACKUP_DIR, so it silently fell back to ./backups while the Hub itself used
the real value from .env. Found in production: postgres's /backups bind
mount was still pinned to a directory orphaned by an earlier git-archive
swap (mv gti-fiscal gti-fiscal_old && mv gti-fiscal_new gti-fiscal — Linux
bind mounts follow the original dentry, not the path string), so every
backup.sh run had been silently landing dumps nobody could find at the
live path. Fixed by pointing BACKUP_DIR at a stable absolute path outside
the deploy tree and recreating postgres once to pick it up; verified with
a real ./backup.sh run in production.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 22:52:53 -03:00
gtiandClaude Sonnet 5 d884d41db5 feat: back up and restore the release-storage volume, not just Postgres
backup.sh now also streams the fiscal-hub container's release binaries
(dist tarball, never in Postgres) into BACKUP_DIR alongside the pg_dump,
with the same 14-backup retention; restore_releases.sh is the companion
restore. Verified with a real restore smoke test in production: the
restored dump's agent_releases row and the restored tarball's exe both
match the published sha256 exactly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 22:49:16 -03:00
gtiandClaude Sonnet 5 e7d77beb26 feat: GTI Gerenciador as the single source of truth for clients; bump to 1.1.2
Tenant gains source (LOCAL|GTI_GERENCIADOR), external_client_id, external_code,
active and synced_at (migration 0024). central/app/client_sync.py fetches from
the panel's new GET /internal/fiscal/clients (dedicated bearer token, never
MySQL credentials) and upserts Tenant rows, never touching a LOCAL row.
/agents/new now offers only active GTI_GERENCIADOR tenants, with a client-side
search box; the POST validates the same rule server-side, not just in the
dropdown. central/scripts/sync_clients_from_gerenciador.py is the operator-run
sync + reconciliation report.

GTI_FISCAL_VERSION/AGENT_VERSION bumped to 1.1.2 (release/VERSION single
source of truth), incorporating the installation_id persistence fix. Rebuilt
the EXE installer trio at 1.1.2 (scripts/build_windows_installer.ps1).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 22:38:58 -03:00
gtiandClaude Sonnet 5 ac7b503c2f fix: persist and recover the Agent's real installation_id (heartbeat activation)
POST /v1/agents/enroll now returns installation_id; new installs persist it
to agent.env immediately. Runtime recovery precedence: existing SQLite
installation_identity -> configured INSTALLATION_ID -> authenticated
GET /v1/agents/me/identity. Recovery fails closed on missing/malformed/
mismatched identity rather than inventing a UUID (which the Hub would then
reject as a conflicting Installation on an already-enrolled Agent). An
explicit AGENT_JOBS_ENABLED gate stops the service from claiming a job right
after the first heartbeat.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 22:13:56 -03:00
gti a9aded1e49 installer v1 (C+D): Windows EXE installer trio + build script + local Hub E2E 2026-09-23 17:44:48 -03:00
gti 91c4030b06 installer v1 (A+B): install-code enrollment, panel code UI, EXE publish; DPAPI credential store 2026-09-23 16:38:19 -03:00
gti b058affa29 docs: windows installer EXE V1 implementation plan 2026-09-23 16:02:30 -03:00