Add 'fiscal/' from commit '102ba84500dbd9655a0471288c3e278652593ca9'

git-subtree-dir: fiscal
git-subtree-mainline: d95165fc8f
git-subtree-split: 102ba84500
This commit is contained in:
gti
2026-09-29 14:43:23 -03:00
868 changed files with 566394 additions and 0 deletions
+142
View File
@@ -0,0 +1,142 @@
"""Acceptance rehearsal of the production scenario on DEV (real HTTP Hub + real Agent worker + Firebird COPY):
product WITHOUT EAN, NCM=00000000, cClassTrib typed by the operator -> visible status (no silent failure) -> an ADMIN decides the NCM of the conflicting GTIN in the KB ->
the flagged re-evaluation finds the unique verified product by NAME -> the Agent writes the NCM (typed write) -> read-back + audit -> second run writes 0.
Also: DRY_RUN shows the candidate without writing; EAN path (KB hit, zero provider requests) with latency; human override is preserved.
docker compose up -d --build fiscal-hub && python scripts/enrichment_acceptance_dev.py
The ADMIN decision is applied through the same code as the panel route (kb.attest + mark_for_reevaluation), with operator name 'E2E-OPERATOR'. Writes go only to the disposable COPY.
"""
import json
import sys
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT)); sys.path.insert(0, str(ROOT / "scripts")); sys.path.insert(0, str(ROOT / "agent" / "src"))
from dotenv import load_dotenv # noqa: E402
load_dotenv(ROOT / ".env")
import enrichment_kb_e2e as ke # noqa: E402
import enrichment_local_hub_e2e as lh # noqa: E402
from gti_fiscal_agent.client import HubClient # noqa: E402
base, ce = ke.base, ke.ce
GTIN = "7894900010015"
def insert(code, name, ncm, ean, cclasstrib):
conn = base.connect(True); cur = conn.cursor()
cur.execute("INSERT INTO C000025 (CODIGO, PRODUTO, CODBARRA, CLASSIFICACAO_FISCAL, CCLASSTRIB) VALUES (?, ?, ?, ?, ?)", (code, name, ean, ncm, cclasstrib))
conn.commit(); conn.close()
def row(code):
conn = base.connect(False); cur = conn.cursor()
cur.execute("SELECT CLASSIFICACAO_FISCAL, CEST, IPI, CCLASSTRIB, PRODUTO FROM C000025 WHERE CODIGO=?", (code,))
r = cur.fetchone(); conn.close()
return tuple(None if v is None else (v if isinstance(v, float) else str(v).strip()) for v in r) if r else None
def ui(code, inst):
return lh.sql(f"select ui_status||'|'||coalesce(reason_code,'') from product_enrichments where product_code='{code}' and installation_id=(select id from installations where installation_id='{inst}')")
def main():
checks, info = {}, {}
base.restore_copy()
c1 = HubClient(lh.HUB, lh.TOKEN)
inst = c1.identity()["installation_id"]
lh.set_features(inst, "DISABLED")
lh.sql(f"delete from product_field_audits where installation_id=(select id from installations where installation_id='{inst}')")
lh.sql(f"delete from product_enrichments where installation_id=(select id from installations where installation_id='{inst}')")
# start from the real situation: the KB has a CONFLICT for the Coca-Cola can (RINCAO x UNIAO), nothing verified
state = ke.exec_hub(f'''
from sqlalchemy import select
from central.app.db import SessionLocal
from central.app.enrichment import kb
from central.app.models import KbKnowledge, KbProduct
with SessionLocal() as s:
p = s.scalar(select(KbProduct).where(KbProduct.gtin == "0{GTIN}"))
rows = s.scalars(select(KbKnowledge).where(KbKnowledge.kb_product_id == p.id, KbKnowledge.knowledge_key == "ncm")).all()
for r in rows: # reset any earlier rehearsal: drop attestation
ev = dict(r.evidence or {{}}); fam = dict(ev.get("families") or {{}}); fam.pop("OPERATOR_ATTESTATION", None); ev["families"] = fam; r.evidence = ev; r.status = "OBSERVED"; r.validated_at = None
s.commit()
print("ROWS", sorted((r.value, r.status) for r in rows))
''')
info["kb_before"] = state
w, stop = ke.worker_for(c1, "acc_dev")
lh.set_features(inst, "DRY_RUN"); w._features_at = -999; time.sleep(6)
# 1) DRY_RUN: product without EAN, placeholder NCM
insert("AC001", "COCA-COLA ORIGINAL LATA 350 ML", "00000000", None, "200004")
time.sleep(12)
info["status_before_decision"] = ui("AC001", inst)
checks["SILENT_FAILURE_FIXED_STATUS_VISIBLE"] = info["status_before_decision"].startswith("EAN_AUSENTE")
checks["NCM_UNCHANGED_UNTIL_DECISION"] = row("AC001")[0] == "00000000"
# 2) ADMIN decision in the KB (same code path as the panel route) -> flagged re-evaluation, still DRY_RUN
out = ke.exec_hub(f'''
from central.app.db import SessionLocal
from central.app.enrichment import history, kb, status
from central.app.models import Installation
from sqlalchemy import select
with SessionLocal() as s:
cur = history.official_sets(s)
r = kb.attest(s, "0{GTIN}", "22021000", "E2E-OPERATOR", lambda v: v in cur, note="E2E rehearsal")
n = 0
for i in s.scalars(select(Installation).where(Installation.enrichment_mode != "DISABLED", Installation.features_configured.is_(True))):
n += status.mark_for_reevaluation(s, i.id)
s.commit()
print("ATTEST", r["status"], r["families"], "flagged", n)
''')
info["attest"] = out
checks["ATTESTED_TO_VERIFIED_KB"] = "VERIFIED_KB" in out
t0 = time.monotonic()
while time.monotonic() - t0 < 40 and not ui("AC001", inst).startswith("SIMULADO"):
time.sleep(1)
info["status_dry_run_after_decision"] = ui("AC001", inst)
checks["DRY_RUN_SHOWS_CANDIDATE_ZERO_WRITES"] = ui("AC001", inst).startswith("SIMULADO") and row("AC001")[0] == "00000000"
# 3) AUTOMATIC: reevaluate (like the panel button) -> written by the Agent
lh.set_features(inst, "ENABLED"); w._features_at = -999; w._auth_cache = (None, 0.0); time.sleep(3)
lh.sql(f"update product_enrichments set reevaluate=true where product_code='AC001' and installation_id=(select id from installations where installation_id='{inst}')")
t0 = time.monotonic()
while time.monotonic() - t0 < 45 and row("AC001")[0] == "00000000":
time.sleep(0.5)
time.sleep(4)
r = row("AC001")
info["AC001_after"] = r
checks["NAME_ONLY_NCM_WRITTEN_BY_AGENT"] = r[0] == "22021000"
checks["CCLASSTRIB_PRESERVED"] = r[3] == "200004"
audit = lh.sql(f"select field||':'||coalesce(old_value,'')||'>'||coalesce(new_value,'')||':'||outcome||':'||coalesce(kb_status,'') from product_field_audits where product_code='AC001' and outcome='APPLIED' order by id")
info["audit"] = audit
checks["AUDIT_OLD_PLACEHOLDER_NEW_NCM"] = "CLASSIFICACAO_FISCAL:00000000>22021000:APPLIED" in audit
checks["FINAL_STATUS_ENRIQUECIDO"] = ui("AC001", inst).startswith("ENRIQUECIDO")
# 4) second run writes 0, zero provider requests
before_req, before_writes = ke.requests_total(), int(lh.sql("select count(*) from product_field_audits where outcome='APPLIED'"))
lh.sql(f"update product_enrichments set reevaluate=true where product_code='AC001' and installation_id=(select id from installations where installation_id='{inst}')")
time.sleep(25)
checks["SECOND_RUN_WRITES_0"] = int(lh.sql("select count(*) from product_field_audits where outcome='APPLIED'")) == before_writes and row("AC001")[0] == "22021000"
checks["ZERO_PROVIDER_REQUESTS_ON_KB_RESOLUTION"] = ke.requests_total() == before_req
# 5) EAN path on the now-verified GTIN: latency + zero provider requests
t0 = time.monotonic()
insert("AC002", "COCA-COLA ORIGINAL LATA 350 ML", "00000000", GTIN, "200004")
while time.monotonic() - t0 < 25 and row("AC002")[0] == "00000000":
time.sleep(0.2)
info["ean_latency_s"] = round(time.monotonic() - t0, 2)
checks["EAN_PATH_KB_HIT_WRITE"] = row("AC002")[0] == "22021000" and ke.requests_total() == before_req
# 6) real NCM preserved + human override preserved
insert("AC003", "COCA-COLA ORIGINAL LATA 350 ML", "19059090", GTIN, "200004"); time.sleep(10)
checks["EXISTING_REAL_NCM_PRESERVED"] = row("AC003")[0] == "19059090"
conn = base.connect(True); cur = conn.cursor(); cur.execute("UPDATE C000025 SET CLASSIFICACAO_FISCAL='19059090' WHERE CODIGO='AC001'"); conn.commit(); conn.close()
time.sleep(E_OVERRIDE_WAIT := 28)
lh.sql(f"update product_enrichments set reevaluate=true where product_code='AC001' and installation_id=(select id from installations where installation_id='{inst}')")
time.sleep(20)
checks["HUMAN_OVERRIDE_PRESERVED"] = row("AC001")[0] == "19059090"
stop.stop = True
result = {"dev_rehearsal": True, "info": info, "checks": checks, "ALL_PASS": all(checks.values())}
(ROOT / "docs" / "runs" / "enrichment_acceptance_dev.json").write_text(json.dumps(result, indent=1, default=str), encoding="utf-8")
print(json.dumps(result, indent=1, default=str))
sys.exit(0 if result["ALL_PASS"] else 1)
if __name__ == "__main__":
main()