3dbd5078e48066b650c19b3ee2cc11a01ca9efcf
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
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). |