diff --git a/.gitignore b/.gitignore
index e5a785b..f55318c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,3 +45,4 @@ scripts/_*
*.pkl
.pytmp/
sources_cache/legal/
+scratch_rtc_e2e/
diff --git a/agent/pyproject.toml b/agent/pyproject.toml
index a08cf8d..fea607c 100644
--- a/agent/pyproject.toml
+++ b/agent/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "gti-fiscal-agent"
-version = "1.1.8"
+version = "1.1.9"
requires-python = ">=3.10"
dependencies = ["httpx>=0.27,<1"]
diff --git a/agent/scripts/run_agent_service.py b/agent/scripts/run_agent_service.py
index dce479f..43710fa 100644
--- a/agent/scripts/run_agent_service.py
+++ b/agent/scripts/run_agent_service.py
@@ -30,7 +30,7 @@ sys.path.insert(0, str(AGENT_ROOT / "src"))
sys.path.insert(0, str(PROJECT_ROOT)) # ships central/app engine modules read-only (central.app.*)
from gti_fiscal_agent.client import HubClient # noqa: E402
-from gti_fiscal_agent import firebird_reader as _firebird_reader, unified_fiscal as _unified # noqa: E402
+from gti_fiscal_agent import firebird_reader as _firebird_reader, rtc_auto_apply as _rtc_apply, unified_fiscal as _unified # noqa: E402
from gti_fiscal_agent.firebird_reader import check_connection, read_products # noqa: E402
from gti_fiscal_agent.pipeline import run_pipeline # noqa: E402
from gti_fiscal_agent.runner import REFERENCE_SCHEMA_V1, product_fingerprint, to_hub_product # noqa: E402
@@ -104,7 +104,10 @@ class Config:
# (A legacy AGENT_JOBS_ENABLED line in an old agent.env is deliberately ignored.)
self.agent_jobs_enabled = True
self.poll_interval_seconds = float(env.get("POLL_INTERVAL_SECONDS", "5"))
- self.agent_version = env.get("AGENT_VERSION", "1.1.8")
+ # RTC auto-apply is a SEPARATE switch (default OFF): FIREBIRD_WRITES alone never lets the Agent fill cClassTrib.
+ self.rtc_auto_apply_enabled = env.get("RTC_AUTO_APPLY_ENABLED", "0").strip() == "1"
+ self.rtc_auto_apply_max_per_job = int(env.get("RTC_AUTO_APPLY_MAX_PER_JOB", str(_rtc_apply.DEFAULT_MAX_PER_JOB)))
+ self.agent_version = env.get("AGENT_VERSION", "1.1.9")
self.schema_fingerprint = env.get("SCHEMA_FINGERPRINT", REFERENCE_SCHEMA_V1)
self.state_db = env.get("AGENT_STATE_DB", str(AGENT_ROOT / "agent_state.sqlite"))
# Pilot write authorization: both must be explicitly set by the installer for
@@ -187,12 +190,12 @@ def open_write_connection(env, database_path, firebird_writes=True):
)
-def _unified_fiscal(env, company):
+def _unified_fiscal(env, company, ncm_valid=None):
"""PIS/COFINS applicability + RTC (only when the ERP has the reform on), read-only (SELECT only). Fail-closed: if it cannot be assessed the job fails
instead of reporting a coverage that ignores these fields."""
connection = _firebird_reader._connect(env)
try:
- return _unified.assess_from_connection(connection, company)
+ return _unified.assess_from_connection(connection, company, ncm_valid=ncm_valid)
finally:
connection.close()
@@ -210,6 +213,28 @@ def _fiscal_blocked_products(products, findings):
return out
+def _rtc_auto_apply(env, config, job, products, fiscal, company):
+ """Report (always) and, only when all three gates are open, fill CCLASSTRIB for products whose class is PROVEN by a deterministic rule.
+ Returns the summary stored in the job result; never raises for a single product."""
+ gate = _rtc_apply.write_gate(firebird_writes=bool(getattr(config, "firebird_writes", False)), agent_enabled=bool(getattr(config, "rtc_auto_apply_enabled", False)),
+ hub_authorized=bool((job.get("authorizations") or {}).get("rtc_auto_apply")))
+ limit = int(getattr(config, "rtc_auto_apply_max_per_job", _rtc_apply.DEFAULT_MAX_PER_JOB))
+ candidates, ready_total = _rtc_apply.select_candidates(fiscal["findings"], products, limit=limit)
+ summary = {"gate": gate, "mode": "AUTO_APPLY" if gate["allowed"] else "REPORT_ONLY", "ready_total": ready_total, "max_per_job": limit, "write_attempts": 0, "write_successes": 0, "applied": [], "aborted": [], "aborted_reasons": {},
+ "allowed_fields": list(_rtc_apply.ALLOWED_RTC_WRITE_FIELDS)}
+ if not (gate["allowed"] and candidates and fiscal["context"].get("rtc_enabled")):
+ return summary
+ from datetime import datetime, timezone
+ connection = open_write_connection(env, config.database_path)
+ try:
+ outcome = _rtc_apply.apply_candidates(connection, candidates, company=company or {}, decision={"local_catalog_hash": fiscal["context"].get("local_catalog_hash")},
+ now=datetime.now(timezone.utc).isoformat(timespec="seconds"), job_id=job.get("job_id"))
+ finally:
+ connection.close()
+ summary.update({k: outcome[k] for k in ("applied", "aborted", "aborted_reasons", "write_attempts", "write_successes")})
+ return summary
+
+
def execute_job(job, config, executor, state, env):
"""Run the pipeline for one claimed job. Never raises for job-domain
failures (bad Firebird read, classify error) — returns (result_summary, error)."""
@@ -249,7 +274,7 @@ def execute_job(job, config, executor, state, env):
if write_connection is not None:
write_connection.close()
- operational = coverage = fiscal_context = None
+ operational = coverage = fiscal_context = rtc_apply = None
fiscal = None
if sync_kind:
if cache:
@@ -261,13 +286,17 @@ def execute_job(job, config, executor, state, env):
all_decisions = decisions
coverage = build_job_coverage(env, client, products, all_decisions)
company = {"crt": ((coverage or {}).get("company_context") or {}).get("company_crt")}
- fiscal = _unified_fiscal(env, company)
+ ncm_ok = {str(p["CODIGO"]): (d or {}).get("status") == "EXACT_NCM" for p, d in zip(products, all_decisions)}
+ fiscal = _unified_fiscal(env, company, ncm_ok)
+ rtc_apply = _rtc_auto_apply(env, config, job, products, fiscal, company)
+ if rtc_apply["write_successes"]:
+ fiscal = _unified_fiscal(env, company, ncm_ok) # coverage must reflect the fields that were just filled
findings = fiscal["findings"]
product_states = [classify_product_state(p, d, fiscal=findings.get(str(p["CODIGO"]))) for p, d in zip(products, all_decisions)]
operational = summarize_operational_states(product_states)
fiscal_context = {**fiscal["context"], "evaluated_all": kind != "REPROCESS_PRODUCTS"}
else:
- fiscal = _unified_fiscal(env, None)
+ fiscal = _unified_fiscal(env, None, {str(p["CODIGO"]): (d or {}).get("status") == "EXACT_NCM" for p, d in zip(to_process, decisions)})
fiscal_blocked = _fiscal_blocked_products(products, fiscal["findings"])
fiscal_codes = {b["product_code"] for b in fiscal_blocked}
summary["blocked_products"] = summary["blocked_products"] + fiscal_blocked
@@ -276,8 +305,9 @@ def execute_job(job, config, executor, state, env):
"coverage": coverage,
"operational": operational,
"fiscal_context": fiscal_context,
+ "rtc_auto_apply": rtc_apply,
"fiscal_mode": getattr(config, "fiscal_mode", None),
- "release_version": env.get("AGENT_VERSION") or "1.1.8",
+ "release_version": env.get("AGENT_VERSION") or "1.1.9",
"products_total": len(products),
"products_changed": len(to_process),
"products_processed": summary["processed"],
@@ -365,7 +395,7 @@ def run(config, env, *, max_iterations=None, stopper=None):
"agent_version": config.agent_version, "last_job_id": last_job_id, "display_name": env.get("AGENT_DISPLAY_NAME", ""),
"customer_code": env.get("CUSTOMER_CODE"), "hostname": env.get("AGENT_HOSTNAME") or os.environ.get("COMPUTERNAME"),
"windows_version": env.get("WINDOWS_VERSION"), "company_code": config.company_id, "company_uf": config.company_uf,
- "database_path": config.database_path, "capabilities": {"heartbeat": True, "jobs": True, "local_logs": True},
+ "database_path": config.database_path, "capabilities": {"heartbeat": True, "jobs": True, "local_logs": True, "rtc_auto_apply": True, "rtc_auto_apply_enabled": bool(getattr(config, "rtc_auto_apply_enabled", False))},
"fiscal_engine_version": env.get("FISCAL_ENGINE_VERSION", config.agent_version), "dataset_versions": {},
}
if hasattr(client, "heartbeat_metadata"):
@@ -435,7 +465,7 @@ def run(config, env, *, max_iterations=None, stopper=None):
def enforce_startup_preflight(env):
"""Full read-only preflight at startup (Hub, auth, Firebird, capabilities, company context, guards). Fail closed."""
from gti_fiscal_agent.preflight import run_preflight
- report = run_preflight(env, agent_version=env.get("AGENT_VERSION") or "1.1.8")
+ report = run_preflight(env, agent_version=env.get("AGENT_VERSION") or "1.1.9")
logger.info("startup preflight: %s", json.dumps({k: report[k] for k in ("PREFLIGHT", "blockers", "fiscal_mode", "effective_firebird_writes")}, ensure_ascii=False))
print(json.dumps({"PREFLIGHT": report["PREFLIGHT"], "blockers": report["blockers"]}, ensure_ascii=False))
if report["PREFLIGHT"] != "PASS":
diff --git a/agent/src/gti_fiscal_agent/preflight.py b/agent/src/gti_fiscal_agent/preflight.py
index d001694..51f63b1 100644
--- a/agent/src/gti_fiscal_agent/preflight.py
+++ b/agent/src/gti_fiscal_agent/preflight.py
@@ -9,7 +9,7 @@ import os
import sqlite3
from pathlib import Path
-AGENT_VERSION_DEFAULT = "1.1.8"
+AGENT_VERSION_DEFAULT = "1.1.9"
REQUIRED_ENV = ("GTI_HUB_URL", "AGENT_TOKEN", "FIREBIRD_DATABASE_PATH", "FB_USER", "FB_PASSWORD")
REQUIRED_CAPABILITIES = ("supports_ncm", "supports_ipi", "supports_cest")
FISCAL_MODES = ("DRY_RUN", "AUTO_APPLY")
diff --git a/agent/src/gti_fiscal_agent/rtc_auto_apply.py b/agent/src/gti_fiscal_agent/rtc_auto_apply.py
new file mode 100644
index 0000000..f6ddd14
--- /dev/null
+++ b/agent/src/gti_fiscal_agent/rtc_auto_apply.py
@@ -0,0 +1,136 @@
+"""RTC auto-apply: fills C000025.CCLASSTRIB, and NOTHING else, when a deterministic rule proves the class.
+
+Safety model (every gate must hold, default is OFF everywhere):
+ FIREBIRD_WRITES effective (FISCAL_MODE=AUTO_APPLY + path/schema authorization) AND RTC_AUTO_APPLY_ENABLED (this Agent) AND Hub authorization (per installation)
+Write allowlist: ALLOWED_RTC_WRITE_FIELDS = ["CCLASSTRIB"]. One short transaction per product. Immediately before the UPDATE the product is re-read and
+the whole decision is re-derived from fresh data; if ANYTHING changed (RTC switch, catalog, NCM, current value, decision) that product is ABORTED.
+An existing value is never overwritten. Every applied change returns an audit record with the old value, so it can be reverted manually and auditably.
+"""
+from __future__ import annotations
+
+import re
+from datetime import date
+
+from central.app.cclasstrib_resolver import compare_catalogs, local_catalog_hash, resolve_cclasstrib
+from central.app.unified_fiscal_coverage import rtc_enabled
+
+from .unified_fiscal import detect_rtc_capabilities, load_rtc_context
+
+ALLOWED_RTC_WRITE_FIELDS = ("CCLASSTRIB",)
+DEFAULT_MAX_PER_JOB = 500
+
+
+class RtcApplyAborted(Exception):
+ """The product is left untouched; `reason` is reported in the audit."""
+
+ def __init__(self, reason: str):
+ super().__init__(reason)
+ self.reason = reason
+
+
+def _text(value) -> str:
+ return "" if value is None else str(value).strip()
+
+
+def _digits(value) -> str:
+ return re.sub(r"\D", "", _text(value))
+
+
+def write_gate(*, firebird_writes: bool, agent_enabled: bool, hub_authorized: bool) -> dict:
+ """{"allowed": bool, "missing": [...]}: writes are possible only when all three switches are on."""
+ missing = [name for name, on in (("FIREBIRD_WRITES", firebird_writes), ("RTC_AUTO_APPLY_ENABLED", agent_enabled), ("HUB_AUTHORIZATION", hub_authorized)) if not on]
+ return {"allowed": not missing, "missing": missing, "firebird_writes": bool(firebird_writes), "agent_enabled": bool(agent_enabled), "hub_authorized": bool(hub_authorized)}
+
+
+def select_candidates(findings: dict, products: list[dict], *, limit: int = DEFAULT_MAX_PER_JOB) -> tuple[list[dict], int]:
+ """Products READY_TO_APPLY: empty CCLASSTRIB + a deterministic resolution, no other RTC problem. Returns (candidates up to `limit`, total ready)."""
+ by_code = {str(p.get("CODIGO") or ""): p for p in products}
+ ready = []
+ for code, found in findings.items():
+ res = found.get("rtc_resolution") or {}
+ if not res.get("auto_apply_candidate"):
+ continue
+ rtc_types = {b["type"] for b in found.get("blockers", []) if b["category"] == "RTC"}
+ if rtc_types != {"CCLASSTRIB_MISSING"}:
+ continue
+ p = by_code.get(code, {})
+ if _text(p.get("CCLASSTRIB")):
+ continue
+ ready.append({"product_code": code, "proposed": res["resolved_cclasstrib"], "cst": res["resolved_cst_ibscbs"], "rule_id": res["rule_id"], "ncm": _digits(p.get("CLASSIFICACAO_FISCAL")), "confidence_type": res["confidence_type"]})
+ return ready[:limit], len(ready)
+
+
+def apply_candidate(conn, candidate: dict, *, company: dict, decision: dict, now: str, job_id=None, today: date | None = None) -> dict:
+ """One product, one short transaction. `decision` = {"local_catalog_hash": ...} captured when the candidate was chosen. Raises RtcApplyAborted (nothing written)."""
+ field = "CCLASSTRIB"
+ assert field in ALLOWED_RTC_WRITE_FIELDS
+ today = today or date.today()
+ code, proposed = candidate["product_code"], candidate["proposed"]
+ cur = conn.cursor()
+ try:
+ schema, catalog, extras = load_rtc_context(cur) # fresh: the ERP is asked again, nothing cached
+ caps = detect_rtc_capabilities(schema, param_value=extras["param_value"], catalog=catalog, physical_fk=extras["physical_fk"])
+ if extras["param_conflict"] or not rtc_enabled(caps):
+ raise RtcApplyAborted("RTC_NO_LONGER_ENABLED")
+ if not caps["RTC_CATALOG_VALID"]:
+ raise RtcApplyAborted("RTC_CATALOG_INVALID")
+ local_rows = (catalog or {}).get("rows") or {}
+ fresh_hash = local_catalog_hash(local_rows)
+ if decision.get("local_catalog_hash") and fresh_hash != decision["local_catalog_hash"]:
+ raise RtcApplyAborted("LOCAL_CATALOG_CHANGED_SINCE_DECISION")
+ cur.execute(f"SELECT {field}, CLASSIFICACAO_FISCAL FROM C000025 WHERE CODIGO = ?", (code,))
+ rows = cur.fetchall()
+ if len(rows) != 1:
+ raise RtcApplyAborted("PRODUCT_ROW_NOT_UNIQUE" if rows else "PRODUCT_NOT_FOUND")
+ current, ncm = _text(rows[0][0]), _digits(rows[0][1])
+ if current:
+ raise RtcApplyAborted("VALUE_ALREADY_SET_NEVER_OVERWRITTEN" if current != proposed else "NO_WRITE_REQUIRED")
+ if ncm != candidate["ncm"]:
+ raise RtcApplyAborted("PRODUCT_CHANGED_NCM")
+ compat = compare_catalogs(local_rows, today)
+ resolution = resolve_cclasstrib({"CODIGO": code, "CLASSIFICACAO_FISCAL": ncm, "ncm_valid": True}, company, {"rtc_enabled": True, "local_catalog_valid": True}, local_rows, compat=compat, today=today)
+ if not resolution.auto_apply_candidate or resolution.resolved_cclasstrib != proposed or resolution.rule_id != candidate["rule_id"]:
+ raise RtcApplyAborted("DECISION_CHANGED")
+ cur.execute(f"UPDATE C000025 SET {field} = ? WHERE CODIGO = ? AND ({field} IS NULL OR TRIM({field}) = '')", (proposed, code))
+ if cur.rowcount != 1:
+ conn.rollback()
+ raise RtcApplyAborted("UPDATE_ROWCOUNT_NOT_ONE")
+ conn.commit()
+ cur = conn.cursor()
+ cur.execute(f"SELECT {field} FROM C000025 WHERE CODIGO = ?", (code,))
+ after = _text(cur.fetchone()[0])
+ conn.commit()
+ if after != proposed:
+ raise RuntimeError(f"post-write verification failed for {code}: {after!r} != {proposed!r}")
+ official = compat["official_catalog"]
+ return {"outcome": "APPLIED", "product_code": code, "field": field, "old_value": None, "new_value": proposed, "cst_ibscbs": resolution.resolved_cst_ibscbs, "rule_id": resolution.rule_id,
+ "confidence_type": resolution.confidence_type, "evidence": {"inputs_used": resolution.inputs_used, "evidence": resolution.evidence[:5], "reason": resolution.reason},
+ "official_source_version": {"cclasstrib_table": official["publication"], "cclasstrib_sha256": official["sha256"], "lc214_sha256": resolution.source_references[0]["sha256"]},
+ "local_catalog_hash": fresh_hash, "timestamp": now, "job_id": job_id, "rowcount": 1, "verified_after": True}
+ except RtcApplyAborted:
+ try:
+ conn.rollback()
+ except Exception: # noqa: BLE001
+ pass
+ raise
+ except Exception:
+ try:
+ conn.rollback()
+ except Exception: # noqa: BLE001
+ pass
+ raise
+
+
+def apply_candidates(conn, candidates: list[dict], *, company: dict, decision: dict, now: str, job_id=None, today: date | None = None) -> dict:
+ """Applies each candidate independently; a failure or an abort never stops the rest and never leaves a partial change."""
+ applied, aborted, reasons = [], [], {}
+ for candidate in candidates:
+ try:
+ applied.append(apply_candidate(conn, candidate, company=company, decision=decision, now=now, job_id=job_id, today=today))
+ except RtcApplyAborted as stop:
+ aborted.append({"outcome": "ABORTED", "product_code": candidate["product_code"], "field": "CCLASSTRIB", "reason": stop.reason, "rule_id": candidate["rule_id"], "job_id": job_id, "timestamp": now})
+ reasons[stop.reason] = reasons.get(stop.reason, 0) + 1
+ except Exception as error: # noqa: BLE001 - technical failure of ONE product must not abort the batch
+ aborted.append({"outcome": "FAILED", "product_code": candidate["product_code"], "field": "CCLASSTRIB", "reason": f"{type(error).__name__}", "rule_id": candidate["rule_id"], "job_id": job_id, "timestamp": now})
+ reasons["TECHNICAL_FAILURE"] = reasons.get("TECHNICAL_FAILURE", 0) + 1
+ return {"applied": applied, "aborted": aborted, "aborted_reasons": reasons, "write_attempts": len(candidates), "write_successes": len(applied)}
diff --git a/agent/src/gti_fiscal_agent/unified_fiscal.py b/agent/src/gti_fiscal_agent/unified_fiscal.py
index 67df3bb..827fe8f 100644
--- a/agent/src/gti_fiscal_agent/unified_fiscal.py
+++ b/agent/src/gti_fiscal_agent/unified_fiscal.py
@@ -11,12 +11,14 @@ import json
from collections import Counter
from datetime import date, datetime, timezone
+from central.app.cclasstrib_resolver import compare_catalogs, local_catalog_hash, resolve_cclasstrib
+from central.app.rtc_findings import refine_rtc_finding, summarize_rtc
from central.app.unified_fiscal_coverage import PIS_COFINS_FIELDS, catalog_integrity, evaluate_product, legal_effective_context, rtc_enabled
PRODUCT_TABLE = "C000025"
RTC_CCLASSTRIB_TABLE = "RTC_CCLASSTRIB"
RTC_CST_TABLE = "RTC_CST"
-PRODUCT_COLUMNS = ("CODIGO", "CCLASSTRIB") + PIS_COFINS_FIELDS + ("PISCOFINS", "INCIDENCIA_PISCOFINS")
+PRODUCT_COLUMNS = ("CODIGO", "CCLASSTRIB", "CLASSIFICACAO_FISCAL") + PIS_COFINS_FIELDS + ("PISCOFINS", "INCIDENCIA_PISCOFINS")
TRUTHY = {"1", "S", "T", "TRUE"}
@@ -67,13 +69,23 @@ def load_rtc_context(cursor) -> tuple[dict, dict | None, dict]:
class_cols = schema.get(RTC_CCLASSTRIB_TABLE, set())
if {"CCLASSTRIB", "CSTIBSCBS"} <= class_cols and "CSTIBSCBS" in schema.get(RTC_CST_TABLE, set()):
validity = "INICIO_VIGENCIA" in class_cols and "FIM_VIGENCIA" in class_cols
- cursor.execute("SELECT TRIM(CCLASSTRIB), TRIM(CSTIBSCBS)" + (", INICIO_VIGENCIA, FIM_VIGENCIA" if validity else "") + " FROM RTC_CCLASSTRIB")
+ extra = [c for c in ("TIPO_ALIQUOTA", "PRED_IBS", "PRED_CBS", "IND_NFE", "IND_NFCE") if c in class_cols]
+ cursor.execute("SELECT TRIM(CCLASSTRIB), TRIM(CSTIBSCBS)" + (", INICIO_VIGENCIA, FIM_VIGENCIA" if validity else "") + "".join(f", {c}" for c in extra) + " FROM RTC_CCLASSTRIB")
rows = cursor.fetchall()
classes = {r[0]: (r[1] or None) for r in rows}
cursor.execute("SELECT TRIM(CSTIBSCBS) FROM RTC_CST")
catalog = {"classes": classes, "cst": {r[0] for r in cursor.fetchall()}, "duplicates": len(rows) - len(classes)}
if validity:
catalog["validity"] = {r[0]: (r[2], r[3]) for r in rows}
+ offset = 4 if validity else 2
+ catalog["rows"] = {r[0]: {"cst": r[1], "start": (r[2] if validity else None), "end": (r[3] if validity else None), **{c: r[offset + i] for i, c in enumerate(extra)}} for r in rows}
+ for value in catalog["rows"].values():
+ for key in ("TIPO_ALIQUOTA", "PRED_IBS", "PRED_CBS", "IND_NFE", "IND_NFCE"):
+ if key in value:
+ value[key.lower()] = value.pop(key)
+ for flag in ("ind_nfe", "ind_nfce"):
+ if flag in value:
+ value[flag] = str(value[flag]).strip() in ("1", "True", "true")
return schema, catalog, extras
@@ -87,9 +99,10 @@ def read_products(cursor, schema: dict) -> list[dict]:
return [dict(zip(columns, row)) for row in cursor.fetchall()]
-def assess_from_connection(conn, company: dict | None, *, today: date | None = None, rtc_override: bool | None = None) -> dict:
+def assess_from_connection(conn, company: dict | None, *, today: date | None = None, rtc_override: bool | None = None, ncm_valid: dict | None = None) -> dict:
"""One read-only pass. Returns {"context": {...}, "findings": {product_code: evaluate_product(...)}}.
- rtc_override forces RTC on/off for simulations WITHOUT touching the ERP parameter (tests / what-if only)."""
+ rtc_override forces RTC on/off for simulations WITHOUT touching the ERP parameter (tests / what-if only).
+ ncm_valid: {product_code: bool} from the decision engine (EXACT_NCM); a product whose NCM is not confirmed never gets a cClassTrib proposal."""
cursor = conn.cursor()
schema, catalog, extras = load_rtc_context(cursor)
caps = detect_rtc_capabilities(schema, param_value=extras["param_value"], catalog=catalog, physical_fk=extras["physical_fk"])
@@ -102,8 +115,15 @@ def assess_from_connection(conn, company: dict | None, *, today: date | None = N
warn_products: set = set()
samples: list = []
applicability: Counter = Counter()
+ local_rows = (catalog or {}).get("rows") or {}
+ compat = compare_catalogs(local_rows, today) if (enabled and local_rows) else None
+ resolver_ctx = {"rtc_enabled": enabled, "local_catalog_valid": bool(caps["RTC_CATALOG_VALID"])}
for p in products:
found = evaluate_product(p, company, rtc, today)
+ if enabled:
+ code0 = str(p.get("CODIGO") or "")
+ resolution = resolve_cclasstrib({**p, "ncm_valid": bool((ncm_valid or {}).get(code0, False))}, company, resolver_ctx, local_rows, compat=compat, today=today)
+ refine_rtc_finding(found, p, resolution, compat["per_code"] if compat else None)
found["input_fingerprint"] = hashlib.sha256(json.dumps({k: (None if v is None else str(v).strip()) for k, v in p.items()} | {"rtc": enabled}, sort_keys=True).encode()).hexdigest()
code = str(p.get("CODIGO") or "")
findings[code] = found
@@ -119,5 +139,7 @@ def assess_from_connection(conn, company: dict | None, *, today: date | None = N
"rtc_observed_at": datetime.now(timezone.utc).isoformat(timespec="seconds"), "legal_effective_context": legal_effective_context((company or {}).get("crt")),
"catalog_integrity": integrity, "crt": (company or {}).get("crt"), "capabilities": caps, "products_evaluated": len(products),
"pis_cofins_applicability": dict(applicability),
+ "rtc_resolution": summarize_rtc(findings, compat) if enabled else None, "local_catalog_hash": local_catalog_hash(local_rows) if local_rows else None,
+ "official_catalog": (compat or {}).get("official_catalog"),
"non_canonical_warnings": {"products": len(warn_products), "by_type": dict(sorted(warn_by_type.items())), "samples": samples}},
"findings": findings}
diff --git a/agent/tests/test_rtc_auto_apply.py b/agent/tests/test_rtc_auto_apply.py
new file mode 100644
index 0000000..db5e7ad
--- /dev/null
+++ b/agent/tests/test_rtc_auto_apply.py
@@ -0,0 +1,297 @@
+import re
+from datetime import date
+
+import pytest
+
+from central.app import rtc_reference_data as ref
+from central.app.cclasstrib_resolver import local_catalog_hash
+from gti_fiscal_agent import rtc_auto_apply as apply_mod
+from gti_fiscal_agent import unified_fiscal as uf
+
+pytestmark = pytest.mark.real_unified_fiscal
+
+TODAY = date(2026, 9, 24)
+NORMAL = {"crt": "3"}
+CLASS_COLS = ("CCLASSTRIB", "CSTIBSCBS", "INICIO_VIGENCIA", "FIM_VIGENCIA", "TIPO_ALIQUOTA", "PRED_IBS", "PRED_CBS", "IND_NFE", "IND_NFCE")
+SCHEMA = ([("C000025", c) for c in ("CODIGO", "CCLASSTRIB", "CLASSIFICACAO_FISCAL", "PISCOFINS", "INCIDENCIA_PISCOFINS")] + [("RTC_CCLASSTRIB", c) for c in CLASS_COLS] + [("RTC_CST", "CSTIBSCBS"), ("PARAMETROS", "USAR_REFORMA_TRIBUTARIA")])
+
+
+class FakeFirebird:
+ """A tiny SGV: PARAMETROS, the RTC catalog (from the official table) and C000025. Every statement is recorded; only SELECT and the single allowed UPDATE are understood."""
+
+ def __init__(self, products, param=(1,), catalog_tweak=None, skip=()):
+ self.products = {c: dict(v) for c, v in products.items()} # code -> {"CCLASSTRIB":..., "CLASSIFICACAO_FISCAL":...}
+ self.param = list(param)
+ self.catalog = {r["code"]: {"cst": r["cst"], "start": r["start"], "end": r["end"], "tipo": r["tipo_aliquota"], "pred_ibs": r["p_red_ibs"], "pred_cbs": r["p_red_cbs"], "ind_nfe": r["ind_nfe"], "ind_nfce": r["ind_nfce"]}
+ for r in ref.OFFICIAL_CCLASSTRIB if r["code"] not in skip and not r["end"]}
+ for code, change in (catalog_tweak or {}).items():
+ self.catalog[code] = {**self.catalog[code], **change}
+ self.cst_table = {r["cst"] for r in ref.OFFICIAL_CCLASSTRIB} # RTC_CST is its own table: a class may point to a CST that is not in it
+ self.statements, self.commits, self.rollbacks = [], 0, 0
+ self._pending = {}
+
+ def cursor(self):
+ return FakeCursor(self)
+
+ def commit(self):
+ for code, value in self._pending.items():
+ self.products[code]["CCLASSTRIB"] = value
+ self._pending = {}
+ self.commits += 1
+
+ def rollback(self):
+ self._pending = {}
+ self.rollbacks += 1
+
+
+class FakeCursor:
+ def __init__(self, db):
+ self.db, self._rows, self.rowcount = db, [], -1
+
+ def execute(self, sql, params=()):
+ db = self.db
+ db.statements.append((sql, tuple(params)))
+ text = " ".join(sql.split())
+ up = text.upper()
+ if up.startswith("SELECT TRIM(RF.RDB$RELATION_NAME)"):
+ self._rows = list(SCHEMA)
+ elif up.startswith("SELECT FIRST 20 USAR_REFORMA_TRIBUTARIA"):
+ self._rows = [(v,) for v in db.param]
+ elif "RDB$RELATION_CONSTRAINTS" in up:
+ self._rows = [(1,)]
+ elif up.startswith("SELECT TRIM(CCLASSTRIB)") and "FROM RTC_CCLASSTRIB" in up:
+ cols = [c.strip() for c in text[len("SELECT "):up.index(" FROM ")].split(",")]
+ rows = []
+ for code, r in db.catalog.items():
+ mapping = {"CSTIBSCBS": r["cst"], "INICIO_VIGENCIA": date.fromisoformat(r["start"]) if r["start"] else None, "FIM_VIGENCIA": None, "TIPO_ALIQUOTA": r["tipo"], "PRED_IBS": r["pred_ibs"],
+ "PRED_CBS": r["pred_cbs"], "IND_NFE": "1" if r["ind_nfe"] else "0", "IND_NFCE": "1" if r["ind_nfce"] else "0"}
+ rows.append(tuple(code if c.startswith("TRIM(CCLASSTRIB") else mapping[re.sub(r"TRIM\((\w+)\)", r"\1", c)] for c in cols))
+ self._rows = rows
+ elif up.startswith("SELECT TRIM(CSTIBSCBS) FROM RTC_CST"):
+ self._rows = [(c,) for c in sorted(db.cst_table)]
+ elif up.startswith("SELECT CODIGO, CCLASSTRIB, CLASSIFICACAO_FISCAL"):
+ self._rows = [(c, v["CCLASSTRIB"], v["CLASSIFICACAO_FISCAL"], "N", "NENHUMA") for c, v in sorted(db.products.items())]
+ elif up.startswith("SELECT CCLASSTRIB, CLASSIFICACAO_FISCAL FROM C000025"):
+ code = params[0]
+ self._rows = [(db.products[code]["CCLASSTRIB"], db.products[code]["CLASSIFICACAO_FISCAL"])] if code in db.products else []
+ if code in db.products and db.products[code].get("DUP"):
+ self._rows = self._rows * 2
+ elif up.startswith("SELECT CCLASSTRIB FROM C000025"):
+ code = params[0]
+ self._rows = [(db.products[code]["CCLASSTRIB"],)]
+ elif up.startswith("UPDATE C000025 SET CCLASSTRIB = ? WHERE CODIGO = ?"):
+ value, code = params
+ product = db.products.get(code)
+ hit = product is not None and not (product["CCLASSTRIB"] or "").strip()
+ self.rowcount = (2 if product and product.get("DUP") else 1) if hit else 0
+ if hit and self.rowcount == 1:
+ db._pending[code] = value
+ else:
+ raise AssertionError(f"unexpected statement: {sql}")
+
+ def fetchall(self):
+ return self._rows
+
+ def fetchone(self):
+ return self._rows[0] if self._rows else None
+
+
+def product(ncm, value=None, **extra):
+ return {"CCLASSTRIB": value, "CLASSIFICACAO_FISCAL": ncm, **extra}
+
+
+def assess(db, ncm_ok=None, company=NORMAL):
+ return uf.assess_from_connection(db, company, today=TODAY, ncm_valid=ncm_ok if ncm_ok is not None else {c: True for c in db.products})
+
+
+def candidates_of(db, limit=500):
+ out = assess(db)
+ products = [{"CODIGO": c, "CCLASSTRIB": v["CCLASSTRIB"], "CLASSIFICACAO_FISCAL": v["CLASSIFICACAO_FISCAL"]} for c, v in db.products.items()]
+ cands, total = apply_mod.select_candidates(out["findings"], products, limit=limit)
+ return out, cands, total
+
+
+def run(db, cands, out, **kw):
+ return apply_mod.apply_candidates(db, cands, company=NORMAL, decision={"local_catalog_hash": out["context"]["local_catalog_hash"]}, now="2026-09-24T20:00:00+00:00", job_id=7, today=TODAY, **kw)
+
+
+PRODUCTS = {"000001": product("10063021"), "000002": product("39235000"), "000003": product("15171000"), "000004": product("30049099"), "000005": product("39235000", "000001")}
+
+
+def test_gate_needs_all_three_switches_and_defaults_to_closed():
+ assert apply_mod.write_gate(firebird_writes=True, agent_enabled=True, hub_authorized=True)["allowed"] is True
+ for combo in ((False, True, True), (True, False, True), (True, True, False), (False, False, False)):
+ g = apply_mod.write_gate(firebird_writes=combo[0], agent_enabled=combo[1], hub_authorized=combo[2])
+ assert g["allowed"] is False and g["missing"]
+ assert apply_mod.ALLOWED_RTC_WRITE_FIELDS == ("CCLASSTRIB",)
+
+
+def test_only_proven_products_become_candidates():
+ db = FakeFirebird(PRODUCTS)
+ out, cands, total = candidates_of(db)
+ assert sorted((c["product_code"], c["proposed"], c["rule_id"]) for c in cands) == [("000001", "200003", "RTC-R3"), ("000002", "000001", "RTC-R4"), ("000003", "200003", "RTC-R3")]
+ assert total == 3 and out["context"]["rtc_resolution"]["ready_to_apply"] == 3 and out["context"]["rtc_resolution"]["ambiguous"] == 1 # medicine chapter is ambiguous
+ assert out["context"]["rtc_resolution"]["valid_existing"] == 1 # 000005 already has the right class
+ assert "000004" not in {c["product_code"] for c in cands}
+
+
+def test_apply_writes_only_cclasstrib_with_audit_and_second_run_writes_nothing():
+ db = FakeFirebird(PRODUCTS)
+ out, cands, _ = candidates_of(db)
+ result = run(db, cands, out)
+ assert result["write_successes"] == 3 and result["write_attempts"] == 3 and result["aborted"] == []
+ assert {c: db.products[c]["CCLASSTRIB"] for c in ("000001", "000002", "000003")} == {"000001": "200003", "000002": "000001", "000003": "200003"}
+ updates = [s for s, _ in db.statements if s.upper().startswith("UPDATE")]
+ assert len(updates) == 3 and all(re.fullmatch(r"UPDATE C000025 SET CCLASSTRIB = \? WHERE CODIGO = \? AND \(CCLASSTRIB IS NULL OR TRIM\(CCLASSTRIB\) = ''\)", u) for u in updates)
+ assert not [s for s, _ in db.statements if re.match(r"(INSERT|DELETE|ALTER|DROP)", s.strip(), re.I)]
+ audit = result["applied"][0]
+ assert {"product_code", "field", "old_value", "new_value", "rule_id", "evidence", "official_source_version", "local_catalog_hash", "timestamp", "job_id", "outcome"} <= set(audit)
+ assert audit["old_value"] is None and audit["field"] == "CCLASSTRIB" and audit["official_source_version"]["cclasstrib_sha256"] == ref.OFFICIAL_CATALOG["sha256"] and audit["job_id"] == 7
+ out2, cands2, total2 = candidates_of(db) # idempotent: nothing left to write
+ assert cands2 == [] and total2 == 0 and out2["context"]["rtc_resolution"]["valid_existing"] == 4
+ before = len(db.statements)
+ assert run(db, cands2, out2)["write_attempts"] == 0 and len(db.statements) == before
+
+
+def test_rtc_switched_off_between_decision_and_write_aborts_every_product():
+ db = FakeFirebird(PRODUCTS)
+ out, cands, _ = candidates_of(db)
+ db.param = [0]
+ result = run(db, cands, out)
+ assert result["write_successes"] == 0 and result["aborted_reasons"] == {"RTC_NO_LONGER_ENABLED": 3} and all(p["CCLASSTRIB"] in (None, "000001") for p in db.products.values())
+
+
+def test_conflicting_parameter_rows_abort():
+ db = FakeFirebird(PRODUCTS)
+ out, cands, _ = candidates_of(db)
+ db.param = [1, 0]
+ assert run(db, cands, out)["aborted_reasons"] == {"RTC_NO_LONGER_ENABLED": 3}
+
+
+def test_catalog_changed_or_invalid_between_decision_and_write_aborts():
+ db = FakeFirebird(PRODUCTS)
+ out, cands, _ = candidates_of(db)
+ db.catalog["200003"]["pred_ibs"] = "60"
+ assert run(db, cands, out)["aborted_reasons"] == {"LOCAL_CATALOG_CHANGED_SINCE_DECISION": 3}
+ db2 = FakeFirebird(PRODUCTS)
+ out2, cands2, _ = candidates_of(db2)
+ db2.catalog["999999"] = {**db2.catalog["000001"], "cst": "555"} # class pointing to a CST that does not exist -> invalid catalog
+ invalid = apply_mod.apply_candidates(db2, cands2, company=NORMAL, decision={}, now="2026-09-24T20:00:00+00:00", job_id=7, today=TODAY) # no hash pinned: integrity check alone must stop it
+ assert invalid["aborted_reasons"] == {"RTC_CATALOG_INVALID": 3}
+
+
+def test_product_changed_between_decision_and_write_is_left_alone():
+ db = FakeFirebird(PRODUCTS)
+ out, cands, _ = candidates_of(db)
+ db.products["000001"]["CLASSIFICACAO_FISCAL"] = "30049099" # NCM edited in the ERP meanwhile
+ db.products["000002"]["CCLASSTRIB"] = "000001" # operator filled it meanwhile (same value)
+ db.products["000003"]["CCLASSTRIB"] = "200034" # ... or with a DIFFERENT value: never overwritten
+ result = run(db, cands, out)
+ assert result["aborted_reasons"] == {"PRODUCT_CHANGED_NCM": 1, "NO_WRITE_REQUIRED": 1, "VALUE_ALREADY_SET_NEVER_OVERWRITTEN": 1} and result["write_successes"] == 0
+ assert db.products["000003"]["CCLASSTRIB"] == "200034" and not [s for s, _ in db.statements if s.upper().startswith("UPDATE")]
+
+
+def test_duplicate_code_rowcount_protection_and_isolation_of_failures():
+ products = {**PRODUCTS, "000002": product("39235000", DUP=True)}
+ db = FakeFirebird(products)
+ out, cands, _ = candidates_of(db)
+ result = run(db, cands, out)
+ assert result["aborted_reasons"] == {"PRODUCT_ROW_NOT_UNIQUE": 1} and result["write_successes"] == 2 # the ambiguous row is skipped, the rest still applied
+ assert db.products["000002"]["CCLASSTRIB"] is None
+
+
+def test_existing_different_valid_class_is_a_conflict_blocker_never_a_write():
+ db = FakeFirebird({"000001": product("10063021", "000001")}) # rice already classified as fully taxed: differs from the proven Anexo I class
+ out = assess(db)
+ types = {b["type"] for b in out["findings"]["000001"]["blockers"]}
+ assert types == {"CCLASSTRIB_CONFLICT"} and out["context"]["rtc_resolution"]["conflicts"] == 1
+ _, cands, _ = candidates_of(db)
+ assert cands == []
+
+
+def test_official_mismatch_of_an_existing_class_is_reported():
+ db = FakeFirebird({"000001": product("39235000", "000001")}, catalog_tweak={"000001": {"ind_nfe": False, "ind_nfce": False}})
+ types = {b["type"] for b in assess(db)["findings"]["000001"]["blockers"]}
+ assert types == {"CCLASSTRIB_OFFICIAL_MISMATCH"}
+
+
+def test_batch_limit_bounds_the_blast_radius():
+ db = FakeFirebird({f"{i:06d}": product("39235000") for i in range(1, 8)})
+ out, cands, total = candidates_of(db, limit=3)
+ assert len(cands) == 3 and total == 7
+
+
+def test_simples_never_produces_candidates_even_with_rtc_on():
+ db = FakeFirebird(PRODUCTS)
+ out = uf.assess_from_connection(db, {"crt": "1"}, today=TODAY, ncm_valid={c: True for c in PRODUCTS})
+ assert out["context"]["rtc_resolution"]["ready_to_apply"] == 0
+ kinds = {b["type"] for f in out["findings"].values() for b in f["blockers"]}
+ assert "CCLASSTRIB_MISSING_UNRESOLVED" in kinds and "CCLASSTRIB_MISSING" not in kinds
+
+
+def test_rtc_off_has_no_resolution_and_no_candidates():
+ db = FakeFirebird(PRODUCTS, param=(0,))
+ out, cands, total = candidates_of(db)
+ assert cands == [] and total == 0 and out["context"]["rtc_resolution"] is None
+
+
+def test_catalog_hash_is_recorded_for_audit():
+ db = FakeFirebird(PRODUCTS)
+ out = assess(db)
+ schema, catalog, _ = uf.load_rtc_context(db.cursor())
+ assert out["context"]["local_catalog_hash"] == local_catalog_hash(catalog["rows"]) and re.fullmatch(r"[0-9a-f]{64}", out["context"]["local_catalog_hash"])
+
+
+# ---------------------------------------------------------------- job integration (gates)
+def _service():
+ from test_run_agent_service import _config, service
+ return service, _config
+
+
+def _fiscal_for(db):
+ return assess(db)
+
+
+def test_job_reports_ready_products_but_writes_nothing_with_default_switches(monkeypatch):
+ service, _config = _service()
+ db = FakeFirebird(PRODUCTS)
+ fiscal = _fiscal_for(db)
+ monkeypatch.setattr(service, "open_write_connection", lambda *a, **k: (_ for _ in ()).throw(AssertionError("no write connection may be opened")))
+ products = [{"CODIGO": c, "CCLASSTRIB": v["CCLASSTRIB"], "CLASSIFICACAO_FISCAL": v["CLASSIFICACAO_FISCAL"]} for c, v in db.products.items()]
+ for cfg_kwargs, auth in (({}, False), ({"firebird_writes": True}, False), ({"firebird_writes": True, "rtc_auto_apply_enabled": True}, False), ({"rtc_auto_apply_enabled": True}, True), ({"firebird_writes": True}, True)):
+ config = _config(**cfg_kwargs)
+ summary = service._rtc_auto_apply({}, config, {"job_id": 1, "authorizations": {"rtc_auto_apply": auth}}, products, fiscal, NORMAL)
+ assert summary["mode"] == "REPORT_ONLY" and summary["gate"]["allowed"] is False and summary["ready_total"] == 3 and summary["write_attempts"] == 0 and summary["applied"] == []
+
+
+def test_job_applies_only_when_all_three_switches_are_open(monkeypatch):
+ service, _config = _service()
+ db = FakeFirebird(PRODUCTS)
+ fiscal = _fiscal_for(db)
+ monkeypatch.setattr(service, "open_write_connection", lambda env, path: _Closeable(db))
+ products = [{"CODIGO": c, "CCLASSTRIB": v["CCLASSTRIB"], "CLASSIFICACAO_FISCAL": v["CLASSIFICACAO_FISCAL"]} for c, v in db.products.items()]
+ config = _config(firebird_writes=True, rtc_auto_apply_enabled=True)
+ summary = service._rtc_auto_apply({}, config, {"job_id": 9, "authorizations": {"rtc_auto_apply": True}}, products, fiscal, NORMAL)
+ assert summary["mode"] == "AUTO_APPLY" and summary["write_successes"] == 3 and summary["allowed_fields"] == ["CCLASSTRIB"] and all(a["job_id"] == 9 for a in summary["applied"])
+ assert [db.products[c]["CCLASSTRIB"] for c in ("000001", "000002", "000003")] == ["200003", "000001", "200003"]
+
+
+def test_job_never_writes_when_the_erp_says_rtc_is_off_even_with_all_switches_open(monkeypatch):
+ service, _config = _service()
+ db = FakeFirebird(PRODUCTS, param=(0,))
+ fiscal = _fiscal_for(db)
+ monkeypatch.setattr(service, "open_write_connection", lambda *a, **k: (_ for _ in ()).throw(AssertionError("no write connection may be opened")))
+ products = [{"CODIGO": c, "CCLASSTRIB": None, "CLASSIFICACAO_FISCAL": "39235000"} for c in db.products]
+ summary = service._rtc_auto_apply({}, _config(firebird_writes=True, rtc_auto_apply_enabled=True), {"job_id": 1, "authorizations": {"rtc_auto_apply": True}}, products, fiscal, NORMAL)
+ assert summary["write_attempts"] == 0 and summary["ready_total"] == 0
+
+
+class _Closeable:
+ def __init__(self, db):
+ self._db = db
+
+ def __getattr__(self, name):
+ return getattr(self._db, name)
+
+ def close(self):
+ pass
diff --git a/agent/tests/test_unified_fiscal.py b/agent/tests/test_unified_fiscal.py
index 7908ea2..bc9a632 100644
--- a/agent/tests/test_unified_fiscal.py
+++ b/agent/tests/test_unified_fiscal.py
@@ -69,14 +69,14 @@ def test_rtc_off_in_the_erp_is_out_of_scope_and_never_blocks():
def test_rtc_on_in_the_erp_brings_cclasstrib_into_the_same_findings():
out = uf.assess_from_connection(FakeConn(param=1), {"crt": "1"}, today=date(2026, 9, 24))
assert out["context"]["rtc_enabled"] is True
- assert kinds(out["findings"]["1"]) == ["CCLASSTRIB_MISSING"] and kinds(out["findings"]["2"]) == []
- assert kinds(out["findings"]["3"]) == ["CCLASSTRIB_MISSING"] # one queue, one verdict per product
+ assert kinds(out["findings"]["1"]) == ["CCLASSTRIB_MISSING_UNRESOLVED"] and kinds(out["findings"]["2"]) == []
+ assert kinds(out["findings"]["3"]) == ["CCLASSTRIB_MISSING_UNRESOLVED"] # one queue, one verdict per product
def test_simulation_flag_never_touches_the_erp_parameter():
conn = FakeConn(param=0)
on = uf.assess_from_connection(conn, {"crt": "1"}, rtc_override=True)
- assert on["context"]["rtc_enabled"] is True and kinds(on["findings"]["1"]) == ["CCLASSTRIB_MISSING"]
+ assert on["context"]["rtc_enabled"] is True and kinds(on["findings"]["1"]) == ["CCLASSTRIB_MISSING_UNRESOLVED"]
assert on["context"]["rtc_param"] == "0" and on["context"]["rtc_source"] == "SIMULATION" and not any("UPDATE" in s.upper() for s in conn.cur.statements)
@@ -124,7 +124,7 @@ def test_toggle_between_syncs_is_followed_in_both_directions_without_any_cache()
assert first["context"]["rtc_enabled"] is False and not [b for f in first["findings"].values() for b in f["blockers"] if b["category"] == "RTC"]
conn.cur.param = 1 # the operator switches the reform on in the ERP between two syncs
second = uf.assess_from_connection(conn, {"crt": "1"})
- assert second["context"]["rtc_enabled"] is True and kinds(second["findings"]["1"]) == ["CCLASSTRIB_MISSING"]
+ assert second["context"]["rtc_enabled"] is True and kinds(second["findings"]["1"]) == ["CCLASSTRIB_MISSING_UNRESOLVED"]
assert second["findings"]["1"]["input_fingerprint"] != first["findings"]["1"]["input_fingerprint"] # a new blocker fingerprint: the old (RTC off) state is not reused
conn.cur.param = 0 # and off again
third = uf.assess_from_connection(conn, {"crt": "1"})
diff --git a/central/alembic/versions/0027_rtc_auto_apply.py b/central/alembic/versions/0027_rtc_auto_apply.py
new file mode 100644
index 0000000..b2ea564
--- /dev/null
+++ b/central/alembic/versions/0027_rtc_auto_apply.py
@@ -0,0 +1,42 @@
+"""RTC auto-apply: per-installation authorization (default OFF) + immutable write audit.
+
+Revision ID: 0027_rtc_auto_apply
+Revises: 0026_central_processing_control
+"""
+from alembic import op
+import sqlalchemy as sa
+
+revision = "0027_rtc_auto_apply"
+down_revision = "0026_central_processing_control"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ op.add_column("installations", sa.Column("rtc_auto_apply_authorized", sa.Boolean(), nullable=False, server_default="false"))
+ op.create_table(
+ "rtc_write_audits",
+ sa.Column("id", sa.Integer(), primary_key=True),
+ sa.Column("tenant_id", sa.Integer(), sa.ForeignKey("tenants.id"), nullable=False, index=True),
+ sa.Column("installation_id", sa.Integer(), sa.ForeignKey("installations.id"), nullable=False, index=True),
+ sa.Column("agent_id", sa.Integer(), sa.ForeignKey("agents.id"), nullable=False, index=True),
+ sa.Column("job_id", sa.Integer(), nullable=True, index=True),
+ sa.Column("client", sa.String(255), nullable=True),
+ sa.Column("product_code", sa.String(64), nullable=False, index=True),
+ sa.Column("field", sa.String(32), nullable=False),
+ sa.Column("outcome", sa.String(16), nullable=False, index=True),
+ sa.Column("reason", sa.String(96), nullable=True),
+ sa.Column("old_value", sa.String(64), nullable=True),
+ sa.Column("new_value", sa.String(64), nullable=True),
+ sa.Column("rule_id", sa.String(32), nullable=True),
+ sa.Column("evidence", sa.JSON(), nullable=False, server_default="{}"),
+ sa.Column("official_source_version", sa.JSON(), nullable=False, server_default="{}"),
+ sa.Column("local_catalog_hash", sa.String(64), nullable=True),
+ sa.Column("written_at", sa.String(40), nullable=True),
+ sa.Column("recorded_at", sa.DateTime(timezone=True), server_default=sa.func.now(), index=True),
+ )
+
+
+def downgrade():
+ op.drop_table("rtc_write_audits")
+ op.drop_column("installations", "rtc_auto_apply_authorized")
diff --git a/central/app/api.py b/central/app/api.py
index 7833832..1a4bbce 100644
--- a/central/app/api.py
+++ b/central/app/api.py
@@ -11,6 +11,7 @@ from .classification import ENGINE_VERSION, Classifier
from .config import settings
from .datasets.service import DatasetService
from .jobs import SYNC_KINDS, claim_next_job, complete_job, create_job, fail_job, schedule_automatic_sync
+from .rtc_audit import record_rtc_write_audits
from .blocked_products import list_blockers, resolve_blocker, resolve_product_blockers, resolve_stale_fiscal_blockers, upsert_blocker
from .context_keys import validate_entry
from .models import AgentSnapshot, BlockedProduct, FiscalContextEntry, ClassificationCache, ClassificationRequest, ClassificationResult, Dataset, Installation, Job
@@ -393,7 +394,9 @@ def router(session_factory, bootstrap_token):
record_event(session, tenant_id=agent.tenant_id, installation_id=installation.id, agent_id=agent.id, severity="INFO", event_type="JOB_STARTED", message=f"Job {job.kind} started", context={"kind": job.kind}, job_id=job.id)
session.commit()
logger.info("job claimed job_id=%s agent_id=%s kind=%s", job.id, agent.id, job.kind)
- return _job_view(job)
+ view = _job_view(job)
+ view["authorizations"] = {"rtc_auto_apply": bool(installation is not None and installation.rtc_auto_apply_authorized)} # decided centrally, per installation, default OFF
+ return view
finally: session.close()
@routes.get("/jobs/global")
@@ -427,6 +430,8 @@ def router(session_factory, bootstrap_token):
upsert_blocker(session, agent.tenant_id, blocker, installation_id=installation.id if installation else None)
for product_code in result_summary.get("resolved_products", []):
resolve_product_blockers(session, agent.tenant_id, product_code, installation_id=installation.id if installation else None)
+ if installation is not None:
+ record_rtc_write_audits(session, tenant_id=agent.tenant_id, installation=installation, agent=agent, job_id=job_id, rtc_auto_apply=result_summary.get("rtc_auto_apply"))
if installation is not None and (result_summary.get("fiscal_context") or {}).get("evaluated_all"):
resolve_stale_fiscal_blockers(session, agent.tenant_id, installation.id, pass_started)
if not complete_job(session, job, result_summary): raise HTTPException(409, "job is not RUNNING")
diff --git a/central/app/cclasstrib_resolver.py b/central/app/cclasstrib_resolver.py
new file mode 100644
index 0000000..4093fde
--- /dev/null
+++ b/central/app/cclasstrib_resolver.py
@@ -0,0 +1,233 @@
+"""Deterministic, auditable cClassTrib resolver (pure: no Firebird, no network, no probabilities).
+
+ resolve_cclasstrib(product, company, ctx, local_catalog) -> Resolution
+
+Nothing here guesses. A class is proposed only when an EXPLICIT rule, backed by the official texts in `rtc_reference_data`
+(cClassTrib table 2026-06-22 and LC 214/2025 compiled through LC 227/2026), proves it. Everything else is AMBIGUOUS or INSUFFICIENT_EVIDENCE.
+
+Operation assumption (documented, product-level default): an ordinary domestic sale of the good. Operation-dependent classes (buyer is a public body,
+exports, ZFM/ALC, credit presumed, ...) cannot be carried by a product default; when the annex offers such alternatives the answer is AMBIGUOUS.
+
+Rules
+ RTC-R0 RTC disabled in the ERP -> NOT_APPLICABLE
+ RTC-R1 Simples family (CRT 1/2/4) -> INSUFFICIENT_EVIDENCE (NT 2025.002 v1.51: orientation for these taxpayers pending)
+ RTC-R2 no valid 8-digit NCM (decision engine did not confirm) -> INSUFFICIENT_EVIDENCE
+ RTC-A1 NCM listed in a REVOKED annex or an annex without a unique product-default class, or under a conditional item text -> AMBIGUOUS
+ RTC-A2 NCM listed in more than one annex -> AMBIGUOUS
+ RTC-A3 NCM in a chapter whose special regime depends on the nature/operation of the good, not on a code list -> AMBIGUOUS
+ RTC-R3 NCM listed in exactly one annex whose product-default class is unique, item text has no condition -> RESOLVED_WITH_EXPLICIT_RULE
+ RTC-R4 NCM listed in NO annex and in no nature-based chapter -> RESOLVED_WITH_EXPLICIT_RULE 000001 (integral taxation, LC 214 art. 4 general rule)
+A proposed class must additionally be present in the local ERP catalog, MATCH the official table, be in force today, be usable in NF-e/NFC-e (the SGV's own
+lookup filter) and carry a CST that exists; otherwise the answer degrades to INSUFFICIENT_EVIDENCE with the exact reason.
+"""
+from __future__ import annotations
+
+import hashlib
+import json
+import re
+from dataclasses import dataclass, field
+from datetime import date
+
+from . import rtc_reference_data as ref
+
+SIMPLES_FAMILY = frozenset({"1", "2", "4"})
+RESOLVED_STATUSES = ("RESOLVED_DETERMINISTIC", "RESOLVED_WITH_EXPLICIT_RULE")
+STATUSES = RESOLVED_STATUSES + ("AMBIGUOUS", "INSUFFICIENT_EVIDENCE", "NOT_APPLICABLE")
+
+# Goods annexes whose product-default class is unique in the official table (verified by `verify_annex_class_map`).
+ANNEX_DEFAULT_CLASS = {"I": "200003", "VII": "200034", "VIII": "200035", "XV": "200014"} # IX is out: 515001 (deferral with the same inputs) is a sibling class
+# Chapters where a reduced/special regime is defined by the NATURE of the good (not by a code list): in natura agriculture (art. 137), medicines (arts. 133/146),
+# fuels and biofuels (art. 172 ff), medical/accessibility devices and vehicles (arts. 131-132, 143-145, 149), books/periodicals (constitutional immunity),
+# gold and other special-regime goods kept out of the residual rule on purpose (conservative).
+SENSITIVE_CHAPTERS = frozenset([f"{n:02d}" for n in range(1, 15)] + ["27", "30", "49", "71", "87", "88", "89", "90"]) # 71 gold (financial-asset regime), 88/89 aircraft and vessels
+SPECIAL_PREFIXES = ("9619", "2207", "3826", "8703") # art. 147 (menstrual health), biofuel inputs, art. 149 (PcD cars)
+
+
+@dataclass
+class Resolution:
+ status: str
+ rule_id: str
+ reason: str
+ resolved_cclasstrib: str | None = None
+ resolved_cst_ibscbs: str | None = None
+ confidence_type: str = "NONE"
+ inputs_used: dict = field(default_factory=dict)
+ evidence: list = field(default_factory=list)
+ source_references: list = field(default_factory=list)
+
+ @property
+ def auto_apply_candidate(self) -> bool:
+ return self.status in RESOLVED_STATUSES and bool(self.resolved_cclasstrib)
+
+ def as_dict(self) -> dict:
+ return {"status": self.status, "rule_id": self.rule_id, "reason": self.reason, "resolved_cclasstrib": self.resolved_cclasstrib, "resolved_cst_ibscbs": self.resolved_cst_ibscbs,
+ "confidence_type": self.confidence_type, "inputs_used": self.inputs_used, "evidence": self.evidence, "source_references": self.source_references,
+ "auto_apply_candidate": self.auto_apply_candidate}
+
+
+def _digits(value) -> str:
+ return re.sub(r"\D", "", "" if value is None else str(value))
+
+
+def _official_by_code() -> dict:
+ return {row["code"]: row for row in ref.OFFICIAL_CCLASSTRIB}
+
+
+def _num(value):
+ try:
+ return float(str(value).replace(",", "."))
+ except (TypeError, ValueError):
+ return None
+
+
+# ------------------------------------------------------------------------------------------------- catalog comparison
+
+
+def compare_catalogs(local_rows: dict, today: date | None = None) -> dict:
+ """local_rows: {code: {cst, tipo_aliquota, p_red_ibs, p_red_cbs, ind_nfe, ind_nfce, start, end}} read from the ERP. Never writes anywhere.
+ Per code: MATCH | LOCAL_ONLY | OFFICIAL_ONLY | MISMATCH | EXPIRED (official table is the reference)."""
+ today = today or date.today()
+ official = _official_by_code()
+ result, details = {}, {}
+ for code in sorted(set(local_rows) | set(official)):
+ loc, off = local_rows.get(code), official.get(code)
+ if off is None:
+ result[code] = "LOCAL_ONLY"
+ elif off.get("end") and date.fromisoformat(off["end"]) < today:
+ result[code] = "EXPIRED"
+ details[code] = ["OFFICIAL_END_PASSED"] + (["PRESENT_LOCALLY"] if loc is not None else [])
+ elif loc is None:
+ result[code] = "OFFICIAL_ONLY"
+ else:
+ problems = []
+ if str(loc.get("cst") or "").strip() != off["cst"]:
+ problems.append("CST")
+ if "p_red_ibs" in loc and "p_red_cbs" in loc and (_num(loc.get("p_red_ibs")) != _num(off["p_red_ibs"]) or _num(loc.get("p_red_cbs")) != _num(off["p_red_cbs"])):
+ problems.append("REDUCTION") # only attributes the local table actually carries are compared
+ if "ind_nfe" in loc and "ind_nfce" in loc and (bool(loc.get("ind_nfe")) != off["ind_nfe"] or bool(loc.get("ind_nfce")) != off["ind_nfce"]):
+ problems.append("DOCUMENT_FLAGS")
+ result[code] = "MISMATCH" if problems else "MATCH"
+ if problems:
+ details[code] = problems
+ counts = {k: sum(1 for v in result.values() if v == k) for k in ("MATCH", "LOCAL_ONLY", "OFFICIAL_ONLY", "MISMATCH", "EXPIRED")}
+ material = counts["MISMATCH"] + counts["LOCAL_ONLY"] # a local class the official table contradicts or does not know
+ expired_present = sum(1 for c, d in details.items() if "PRESENT_LOCALLY" in d)
+ compat = "FULL" if counts["OFFICIAL_ONLY"] == 0 and expired_present == 0 and material == 0 else ("PARTIAL_LOCAL_OUTDATED" if material == 0 else "MATERIAL_MISMATCH")
+ return {"per_code": result, "details": details, "counts": counts, "expired_present_locally": expired_present, "compatibility": compat,
+ "official_catalog": {"sha256": ref.OFFICIAL_CATALOG["sha256"], "publication": ref.OFFICIAL_CATALOG["publication"], "file": ref.OFFICIAL_CATALOG["file"]}}
+
+
+def local_catalog_hash(local_rows: dict) -> str:
+ canon = json.dumps({c: {k: (None if v is None else str(v)) for k, v in sorted(r.items())} for c, r in sorted(local_rows.items())}, sort_keys=True)
+ return hashlib.sha256(canon.encode()).hexdigest()
+
+
+def verify_annex_class_map() -> dict:
+ """Self-check of ANNEX_DEFAULT_CLASS against the official table: the class must exist, be a goods class in force, and be the ONLY official class for that annex
+ usable in NF-e/NFC-e as the ordinary-sale default. Returns {annex: [problems]} (empty lists = verified)."""
+ official = _official_by_code()
+ numbers = {"I": "1", "VII": "7", "VIII": "8", "XV": "15"}
+ out = {}
+ for annex, code in ANNEX_DEFAULT_CLASS.items():
+ row, problems = official.get(code), []
+ if row is None:
+ problems.append("CLASS_NOT_IN_OFFICIAL_TABLE")
+ else:
+ if str(row.get("anexo")) != numbers[annex]:
+ problems.append("ANNEX_FIELD_DIFFERS")
+ if not (row["ind_nfe"] or row["ind_nfce"]):
+ problems.append("NOT_USABLE_IN_NFE_NFCE")
+ siblings = [r["code"] for r in ref.OFFICIAL_CCLASSTRIB if str(r.get("anexo")) == numbers[annex] and r["code"] != code and (r["ind_nfe"] or r["ind_nfce"])]
+ if siblings:
+ problems.append("SIBLING_CLASSES:" + ",".join(siblings))
+ out[annex] = problems
+ return out
+
+
+# ------------------------------------------------------------------------------------------------- annex lookup
+
+
+def annex_matches(ncm: str) -> list[dict]:
+ """Every annex item (any annex, revoked included) whose code list covers the NCM, with the item text and whether it is a clean (condition-free) item."""
+ hits = []
+ for roman, annex in ref.LC214_ANNEXES.items():
+ for item in annex["items"]:
+ for prefix in item["prefixes"]:
+ if ncm.startswith(prefix):
+ hits.append({"annex": roman, "item": item["item"], "prefix": prefix, "clean": item["clean"], "revoked": annex["revoked"], "text": item["description"][:160]})
+ break
+ return hits
+
+
+def _references(extra=None) -> list:
+ refs = [{"document": ref.LC214_SOURCE["document"], "url": ref.LC214_SOURCE["url"], "sha256": ref.LC214_SOURCE["sha256"]},
+ {"document": "cClassTrib (Portal Nacional NF-e)", "publication": ref.OFFICIAL_CATALOG["publication"], "sha256": ref.OFFICIAL_CATALOG["sha256"]}]
+ return refs + (extra or [])
+
+
+def _validate_class(code: str, local_rows: dict, compat: dict, today: date):
+ """None when the class may be proposed, else the exact reason it may not."""
+ official = _official_by_code().get(code)
+ if official is None:
+ return "CLASS_NOT_IN_OFFICIAL_TABLE"
+ loc = local_rows.get(code)
+ if loc is None:
+ return "CLASS_NOT_IN_LOCAL_CATALOG"
+ state = compat["per_code"].get(code)
+ if state != "MATCH":
+ return f"LOCAL_OFFICIAL_{state}"
+ if official["start"] and date.fromisoformat(official["start"]) > today:
+ return "CLASS_NOT_YET_IN_FORCE"
+ if not (official["ind_nfe"] or official["ind_nfce"]):
+ return "CLASS_NOT_USABLE_IN_NFE_NFCE"
+ return None
+
+
+# ------------------------------------------------------------------------------------------------- resolver
+
+
+def resolve_cclasstrib(product: dict, company: dict | None, ctx: dict, local_rows: dict | None, *, compat: dict | None = None, today: date | None = None) -> Resolution:
+ """product: {"CODIGO","CLASSIFICACAO_FISCAL","ncm_valid"(bool)}; company: {"crt"}; ctx: {"rtc_enabled": bool, "local_catalog_valid": bool}."""
+ today = today or date.today()
+ ncm = _digits(product.get("CLASSIFICACAO_FISCAL"))
+ crt = str((company or {}).get("crt") or "").strip()
+ used = {"ncm": ncm or None, "crt": crt or None, "rtc_enabled": bool(ctx.get("rtc_enabled"))}
+ if not ctx.get("rtc_enabled"):
+ return Resolution("NOT_APPLICABLE", "RTC-R0", "RTC_DISABLED_IN_ERP", inputs_used=used)
+ if not ctx.get("local_catalog_valid"):
+ return Resolution("INSUFFICIENT_EVIDENCE", "RTC-G1", "LOCAL_RTC_CATALOG_INVALID", inputs_used=used)
+ if crt in SIMPLES_FAMILY:
+ return Resolution("INSUFFICIENT_EVIDENCE", "RTC-R1", "SIMPLES_ORIENTATION_PENDING_OFFICIAL_NT", inputs_used=used,
+ source_references=_references([{"document": "NT 2025.002-RTC v1.51 (Portal NF-e, 04/08/2026)", "note": "IBS/CBS orientations for CRT 1/2/4 pending; taxation from 2027 (LC 214 art. 348)"}]))
+ if not crt:
+ return Resolution("INSUFFICIENT_EVIDENCE", "RTC-R1", "COMPANY_REGIME_UNKNOWN", inputs_used=used)
+ if len(ncm) != 8 or product.get("ncm_valid") is not True:
+ return Resolution("INSUFFICIENT_EVIDENCE", "RTC-R2", "NO_VALID_NCM", inputs_used=used)
+ local_rows = local_rows or {}
+ compat = compat or compare_catalogs(local_rows, today)
+ hits = annex_matches(ncm)
+ annexes = sorted({h["annex"] for h in hits})
+ if hits:
+ if any(h["revoked"] for h in hits) and len(annexes) == 1:
+ return Resolution("AMBIGUOUS", "RTC-A1", "LISTED_ONLY_IN_REVOKED_ANNEX", inputs_used=used, evidence=hits, source_references=_references())
+ live = [h for h in hits if not h["revoked"]]
+ live_annexes = sorted({h["annex"] for h in live})
+ if len(live_annexes) > 1 or (len(live_annexes) == 1 and len(annexes) > 1):
+ return Resolution("AMBIGUOUS", "RTC-A2", "LISTED_IN_MORE_THAN_ONE_ANNEX", inputs_used=used, evidence=hits, source_references=_references())
+ annex = live_annexes[0] if live_annexes else annexes[0]
+ clean = [h for h in live if h["clean"]]
+ cls = ANNEX_DEFAULT_CLASS.get(annex)
+ if not cls or not clean or len(clean) != len(live):
+ return Resolution("AMBIGUOUS", "RTC-A1", f"ANNEX_{annex}_NEEDS_OPERATION_OR_CONDITION", inputs_used=used, evidence=hits, source_references=_references())
+ problem = _validate_class(cls, local_rows, compat, today)
+ if problem:
+ return Resolution("INSUFFICIENT_EVIDENCE", "RTC-G2", problem, inputs_used=used, evidence=hits, source_references=_references())
+ official = _official_by_code()[cls]
+ return Resolution("RESOLVED_WITH_EXPLICIT_RULE", "RTC-R3", f"ANNEX_{annex}_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS", cls, official["cst"], "ANNEX_TEXT_MATCH", used, hits, _references())
+ if ncm[:2] in SENSITIVE_CHAPTERS or ncm.startswith(SPECIAL_PREFIXES):
+ return Resolution("AMBIGUOUS", "RTC-A3", "SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD", inputs_used=used, evidence=[{"chapter": ncm[:2]}], source_references=_references())
+ problem = _validate_class("000001", local_rows, compat, today)
+ if problem:
+ return Resolution("INSUFFICIENT_EVIDENCE", "RTC-G2", problem, inputs_used=used, source_references=_references())
+ return Resolution("RESOLVED_WITH_EXPLICIT_RULE", "RTC-R4", "NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER", "000001", "000", "EXCLUSION_OF_ALL_SPECIAL_REGIMES", used,
+ [{"annex_hits": 0, "chapter": ncm[:2]}], _references())
diff --git a/central/app/events.py b/central/app/events.py
index 7e532c1..b6e0954 100644
--- a/central/app/events.py
+++ b/central/app/events.py
@@ -15,7 +15,7 @@ EVENT_TYPES = {
"AGENT_STARTED", "AGENT_STOPPED", "HEARTBEAT", "PREFLIGHT_PASS", "PREFLIGHT_FAIL", "JOB_CLAIMED", "JOB_STARTED",
"JOB_COMPLETED", "JOB_FAILED", "PRODUCT_BLOCKED", "BLOCKER_RESOLVED", "DATASET_CHANGED", "COMPANY_CONTEXT_CHANGED",
"SCHEMA_CHANGED", "WRITE_PLANNED", "WRITE_COMPLETED", "WRITE_FAILED", "CONNECTION_ERROR", "RETRY", "VERSION_CHANGED",
- "WINDOWS_INSTALL_COMPLETED", "WINDOWS_UNINSTALL_COMPLETED", "ADMIN_ACTION",
+ "WINDOWS_INSTALL_COMPLETED", "WINDOWS_UNINSTALL_COMPLETED", "ADMIN_ACTION", "RTC_AUTO_APPLY",
}
SEVERITIES = {"INFO", "WARNING", "ERROR", "CRITICAL"}
SECRET_RE = re.compile(r"(?i)(password|fb_password|token|api[_-]?key|secret|authorization|connection[_-]?string)\s*[:=]\s*[^,;\s]+")
diff --git a/central/app/models.py b/central/app/models.py
index 8043b2e..ec2debc 100644
--- a/central/app/models.py
+++ b/central/app/models.py
@@ -282,6 +282,8 @@ class Installation(Base):
sync_interval_seconds: Mapped[int] = mapped_column(Integer, default=1800, server_default="1800")
last_sync_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
last_sync_changed: Mapped[int | None] = mapped_column(Integer, nullable=True)
+ # RTC auto-apply is authorized centrally per installation and is OFF until an operator explicitly turns it on (the Agent has its own second switch).
+ rtc_auto_apply_authorized: Mapped[bool] = mapped_column(Boolean, default=False, server_default="false")
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
@@ -731,3 +733,26 @@ class ExternalProductCache(Base):
normalized_data: Mapped[dict] = mapped_column(JSON, default=dict)
cache_allowed: Mapped[bool] = mapped_column(Boolean, default=False)
redistribution_allowed: Mapped[bool] = mapped_column(Boolean, default=False)
+
+
+class RtcWriteAudit(Base):
+ """Append-only record of every attempted C000025.CCLASSTRIB write (applied or aborted). Holds the old value, so each change is revertible by hand."""
+ __tablename__ = "rtc_write_audits"
+ id: Mapped[int] = mapped_column(primary_key=True)
+ tenant_id: Mapped[int] = mapped_column(ForeignKey("tenants.id"), index=True)
+ installation_id: Mapped[int] = mapped_column(ForeignKey("installations.id"), index=True)
+ agent_id: Mapped[int] = mapped_column(ForeignKey("agents.id"), index=True)
+ job_id: Mapped[int | None] = mapped_column(Integer, nullable=True, index=True)
+ client: Mapped[str | None] = mapped_column(String(255), nullable=True)
+ product_code: Mapped[str] = mapped_column(String(64), index=True)
+ field: Mapped[str] = mapped_column(String(32))
+ outcome: Mapped[str] = mapped_column(String(16), index=True)
+ reason: Mapped[str | None] = mapped_column(String(96), nullable=True)
+ old_value: Mapped[str | None] = mapped_column(String(64), nullable=True)
+ new_value: Mapped[str | None] = mapped_column(String(64), nullable=True)
+ rule_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
+ evidence: Mapped[dict] = mapped_column(JSON, default=dict)
+ official_source_version: Mapped[dict] = mapped_column(JSON, default=dict)
+ local_catalog_hash: Mapped[str | None] = mapped_column(String(64), nullable=True)
+ written_at: Mapped[str | None] = mapped_column(String(40), nullable=True)
+ recorded_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True)
diff --git a/central/app/panel_presentation.py b/central/app/panel_presentation.py
index f63d3ec..324f8a4 100644
--- a/central/app/panel_presentation.py
+++ b/central/app/panel_presentation.py
@@ -161,7 +161,7 @@ def priority_label(value):
return _human_label(value, {"CRITICAL": "Crítica", "HIGH": "Alta", "NORMAL": "Média", "MEDIUM": "Média", "LOW": "Baixa"})
-def rtc_status_view(summary):
+def rtc_status_view(summary, authorized=False):
"""Discreet Reforma Tributaria status from the last completed job's `fiscal_context`, exactly as the Agent OBSERVED it in that installation's own database.
None when the Agent did not report it (older Agents)."""
context = (summary or {}).get("fiscal_context") if isinstance(summary, dict) else None
@@ -174,6 +174,36 @@ def rtc_status_view(summary):
except ValueError:
observed = None
source = context.get("rtc_source") or "PARAMETROS.USAR_REFORMA_TRIBUTARIA"
- return {"enabled": bool(context["rtc_enabled"]), "label": "Ativa" if context["rtc_enabled"] else "Desativada", "supported": bool(context.get("rtc_supported")),
+ products = _rtc_products_view(context.get("rtc_resolution"), bool(context["rtc_enabled"]))
+ return {"products": products, "apply": _rtc_apply_view(summary.get("rtc_auto_apply"), authorized), "enabled": bool(context["rtc_enabled"]), "label": "Ativa" if context["rtc_enabled"] else "Desativada", "supported": bool(context.get("rtc_supported")),
"catalog_valid": bool(context.get("rtc_catalog_valid")), "observed_at": observed, "conflict": bool(context.get("rtc_param_conflict")),
"title": f"Lido no banco do cliente ({source})" + (f" em {observed}" if observed else "") + (" - linhas de PARAMETROS divergentes: RTC tratada como desativada" if context.get("rtc_param_conflict") else "")}
+
+
+def _rtc_products_view(resolution, enabled):
+ """Compact 'Produtos RTC' summary. None when RTC is off (RTC never shows up as a problem) or the Agent did not report a resolution."""
+ if not enabled or not isinstance(resolution, dict) or not resolution.get("total"):
+ return None
+ total = int(resolution["total"])
+ valid = int(resolution.get("valid_existing", 0))
+ ready = int(resolution.get("ready_to_apply", 0))
+ blocked = total - valid - ready
+ pending = total - valid
+ return {"total": total, "valid": valid, "ready": ready, "blocked": blocked, "pending": pending,
+ "headline": f"Reforma Tributária ativa — cClassTrib pendente em {pending} produto{'s' if pending != 1 else ''}" if pending else "Reforma Tributária ativa — todos os produtos com cClassTrib válido",
+ "catalog": (resolution.get("catalog_compatibility") or {}).get("compatibility")}
+
+
+def _rtc_apply_view(report, authorized):
+ """State of the (default OFF) automatic fill, for the operator. Never claims a write happened unless the Agent reported it."""
+ gate = (report or {}).get("gate") or {}
+ applied = len((report or {}).get("applied") or [])
+ missing = gate.get("missing") or []
+ labels = {"FIREBIRD_WRITES": "escrita no Firebird desligada no Agent", "RTC_AUTO_APPLY_ENABLED": "chave RTC_AUTO_APPLY_ENABLED desligada no Agent", "HUB_AUTHORIZATION": "sem autorização no Hub"}
+ if gate.get("allowed"):
+ state = "Ativo"
+ elif authorized:
+ state = "Autorizado no Hub, aguardando o Agent (" + "; ".join(labels.get(m, m) for m in missing if m != "HUB_AUTHORIZATION") + ")" if any(m != "HUB_AUTHORIZATION" for m in missing) else "Autorizado no Hub"
+ else:
+ state = "Desativado"
+ return {"authorized": bool(authorized), "state": state, "applied_last_job": applied, "aborted_last_job": len((report or {}).get("aborted") or []), "mode": (report or {}).get("mode")}
diff --git a/central/app/rtc_audit.py b/central/app/rtc_audit.py
new file mode 100644
index 0000000..3c5a217
--- /dev/null
+++ b/central/app/rtc_audit.py
@@ -0,0 +1,36 @@
+"""Persists the Agent's RTC auto-apply audit records (append-only) and mirrors a summary event for the panel."""
+from __future__ import annotations
+
+from .events import record_event
+from .models import RtcWriteAudit
+
+MAX_AUDITS_PER_JOB = 2000
+
+
+def record_rtc_write_audits(session, *, tenant_id: int, installation, agent, job_id: int | None, rtc_auto_apply: dict | None) -> int:
+ """Stores every applied/aborted write of the job. Never trusts the Agent for identity: tenant/installation/agent come from the authenticated context."""
+ if not isinstance(rtc_auto_apply, dict):
+ return 0
+ records = list(rtc_auto_apply.get("applied") or []) + list(rtc_auto_apply.get("aborted") or [])
+ stored = applied = aborted = 0
+ for item in records[:MAX_AUDITS_PER_JOB]:
+ if not isinstance(item, dict) or item.get("field") != "CCLASSTRIB":
+ continue
+ session.add(RtcWriteAudit(
+ tenant_id=tenant_id, installation_id=installation.id, agent_id=agent.id, job_id=job_id, client=getattr(installation, "display_name", None),
+ product_code=str(item.get("product_code", ""))[:64], field="CCLASSTRIB", outcome=str(item.get("outcome", ""))[:16], reason=(item.get("reason") or None) and str(item["reason"])[:96],
+ old_value=(None if item.get("old_value") is None else str(item["old_value"])[:64]), new_value=(None if item.get("new_value") is None else str(item["new_value"])[:64]),
+ rule_id=(item.get("rule_id") or None) and str(item["rule_id"])[:32], evidence=item.get("evidence") or {}, official_source_version=item.get("official_source_version") or {},
+ local_catalog_hash=item.get("local_catalog_hash"), written_at=item.get("timestamp")))
+ stored += 1
+ if item.get("outcome") == "APPLIED":
+ applied += 1
+ else:
+ aborted += 1
+ if stored:
+ record_event(session, tenant_id=tenant_id, installation_id=installation.id, agent_id=agent.id, severity="WARNING" if applied else "INFO", event_type="RTC_AUTO_APPLY", job_id=job_id,
+ message=f"cClassTrib preenchido em {applied} produto(s); {aborted} abortado(s)",
+ context={"applied": applied, "aborted": aborted, "reasons": rtc_auto_apply.get("aborted_reasons") or {}, "mode": rtc_auto_apply.get("mode")})
+ if stored:
+ session.commit()
+ return stored
diff --git a/central/app/rtc_findings.py b/central/app/rtc_findings.py
new file mode 100644
index 0000000..059aa4d
--- /dev/null
+++ b/central/app/rtc_findings.py
@@ -0,0 +1,90 @@
+"""Turns the deterministic cClassTrib resolution into the ONE root-cause RTC finding per product (pure).
+
+`evaluate_product` (unified_fiscal_coverage) says WHETHER a product violates the RTC rule; this module says WHY and whether the gap is closable:
+the single RTC blocker of a product is refined to the cause that matters, never several blockers for the same root cause.
+"""
+from __future__ import annotations
+
+from .cclasstrib_resolver import Resolution
+
+RTC_CATALOG_REASONS = ("LOCAL_OFFICIAL_", "CLASS_NOT_IN_LOCAL_CATALOG", "CLASS_NOT_IN_OFFICIAL_TABLE", "CLASS_NOT_YET_IN_FORCE", "CLASS_NOT_USABLE_IN_NFE_NFCE", "LOCAL_RTC_CATALOG_INVALID")
+EVIDENCE_REASONS = ("NO_VALID_NCM", "COMPANY_REGIME_UNKNOWN")
+RTC_TYPES = ("CCLASSTRIB_MISSING", "CCLASSTRIB_MISSING_UNRESOLVED", "CCLASSTRIB_AMBIGUOUS", "CCLASSTRIB_CONFLICT", "CCLASSTRIB_OFFICIAL_MISMATCH", "RTC_LOCAL_CATALOG_OUTDATED",
+ "RTC_RULE_EVIDENCE_MISSING", "CCLASSTRIB_INVALID_FORMAT", "CCLASSTRIB_NOT_IN_CATALOG", "RTC_CST_MISSING", "RTC_CATALOG_INVALID")
+
+
+def _text(value) -> str:
+ return "" if value is None else str(value).strip()
+
+
+def slim(resolution: Resolution) -> dict:
+ """Small, audit-grade view kept in the job result (full evidence stays in the resolver output)."""
+ return {"status": resolution.status, "rule_id": resolution.rule_id, "reason": resolution.reason, "resolved_cclasstrib": resolution.resolved_cclasstrib,
+ "resolved_cst_ibscbs": resolution.resolved_cst_ibscbs, "confidence_type": resolution.confidence_type, "auto_apply_candidate": resolution.auto_apply_candidate}
+
+
+def refine_rtc_finding(found: dict, product: dict, resolution: Resolution | None, compat_state: dict | None) -> dict:
+ """Mutates and returns `found` (an `evaluate_product` result). Only acts when RTC is REQUIRED for the product."""
+ if found.get("applicability", {}).get("RTC") != "REQUIRED" or resolution is None:
+ return found
+ value = _text(product.get("CCLASSTRIB"))
+ rtc_blockers = [b for b in found["blockers"] if b["category"] == "RTC"]
+ kinds = {b["type"] for b in rtc_blockers}
+ found["rtc_resolution"] = slim(resolution)
+ if "RTC_CATALOG_INVALID" in kinds:
+ return found # nothing can be proposed or compared against an invalid catalog
+ others = [b for b in found["blockers"] if b["category"] != "RTC"]
+ if "CCLASSTRIB_MISSING" in kinds:
+ if resolution.auto_apply_candidate:
+ new = ("CCLASSTRIB_MISSING", f"READY_TO_APPLY:{resolution.resolved_cclasstrib}:{resolution.rule_id}")
+ elif resolution.status == "AMBIGUOUS":
+ new = ("CCLASSTRIB_AMBIGUOUS", f"{resolution.rule_id}:{resolution.reason}")
+ elif resolution.reason.startswith(RTC_CATALOG_REASONS):
+ new = ("RTC_LOCAL_CATALOG_OUTDATED", resolution.reason)
+ elif resolution.reason in EVIDENCE_REASONS:
+ new = ("RTC_RULE_EVIDENCE_MISSING", resolution.reason)
+ else:
+ new = ("CCLASSTRIB_MISSING_UNRESOLVED", f"{resolution.rule_id}:{resolution.reason}")
+ found["blockers"] = others + [{"type": new[0], "category": "RTC", "reason": new[1]}]
+ return found
+ if not rtc_blockers and value: # a valid existing class: compare, never overwrite
+ state = (compat_state or {}).get(value)
+ if state in ("MISMATCH", "EXPIRED", "LOCAL_ONLY"):
+ found["blockers"] = others + [{"type": "CCLASSTRIB_OFFICIAL_MISMATCH", "category": "RTC", "reason": f"LOCAL_VS_OFFICIAL:{state}"}]
+ elif resolution.auto_apply_candidate and resolution.resolved_cclasstrib != value:
+ found["blockers"] = others + [{"type": "CCLASSTRIB_CONFLICT", "category": "RTC", "reason": f"HAS:{value};RULE:{resolution.rule_id}:{resolution.resolved_cclasstrib}"}]
+ else:
+ found["rtc_resolution"]["no_write_required"] = resolution.auto_apply_candidate and resolution.resolved_cclasstrib == value
+ return found
+
+
+def summarize_rtc(findings: dict, compat: dict | None = None) -> dict:
+ """Counts for the panel and the audit: how many products already have a valid class, how many are ready to be filled, how many are blocked and why."""
+ out = {"total": 0, "valid_existing": 0, "ready_to_apply": 0, "ambiguous": 0, "insufficient": 0, "conflicts": 0, "official_mismatch": 0, "not_applicable": 0, "other_blocked": 0, "by_rule": {}, "by_reason": {}}
+ for found in findings.values():
+ out["total"] += 1
+ if found.get("applicability", {}).get("RTC") != "REQUIRED":
+ out["not_applicable"] += 1
+ continue
+ types = {b["type"] for b in found["blockers"] if b["category"] == "RTC"}
+ res = found.get("rtc_resolution") or {}
+ if res:
+ out["by_rule"][res["rule_id"]] = out["by_rule"].get(res["rule_id"], 0) + 1
+ out["by_reason"][res["reason"]] = out["by_reason"].get(res["reason"], 0) + 1
+ if not types:
+ out["valid_existing"] += 1
+ elif "CCLASSTRIB_CONFLICT" in types:
+ out["conflicts"] += 1
+ elif "CCLASSTRIB_OFFICIAL_MISMATCH" in types:
+ out["official_mismatch"] += 1
+ elif res.get("auto_apply_candidate") and "CCLASSTRIB_MISSING" in types:
+ out["ready_to_apply"] += 1
+ elif "CCLASSTRIB_AMBIGUOUS" in types:
+ out["ambiguous"] += 1
+ elif types & {"CCLASSTRIB_MISSING_UNRESOLVED", "RTC_RULE_EVIDENCE_MISSING", "RTC_LOCAL_CATALOG_OUTDATED", "CCLASSTRIB_MISSING"}:
+ out["insufficient"] += 1
+ else:
+ out["other_blocked"] += 1
+ if compat:
+ out["catalog_compatibility"] = {"compatibility": compat["compatibility"], "counts": compat["counts"], "expired_present_locally": compat.get("expired_present_locally", 0)}
+ return out
diff --git a/central/app/rtc_reference_data.py b/central/app/rtc_reference_data.py
new file mode 100644
index 0000000..39f8e97
--- /dev/null
+++ b/central/app/rtc_reference_data.py
@@ -0,0 +1,2735 @@
+"""GENERATED by scripts/build_rtc_reference_data.py - do not edit. Official cClassTrib catalog and LC 214/2025 goods annexes with provenance."""
+
+OFFICIAL_CATALOG = {'file': 'cClassTrib 2026-06-22.xlsx',
+ 'parser': 'rtc-cclasstrib-xlsx-v1',
+ 'publication': '2026-06-22',
+ 'sha256': '1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654',
+ 'source': 'Portal Nacional da NF-e (cClassTrib)'}
+
+OFFICIAL_CCLASSTRIB = [{'anexo': None,
+ 'code': '000001',
+ 'cst': '000',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Situações tributadas integralmente pelo IBS e CBS.',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '90111', 'code': '000002', 'cst': '000', 'end': None, 'ind_nfce': False, 'ind_nfe': False, 'name': 'Exploração de via', 'p_red_cbs': '0', 'p_red_ibs': '0', 'start': '2026-01-01', 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '000003',
+ 'cst': '000',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regime automotivo - projetos incentivados (art. 311)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '000004',
+ 'cst': '000',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regime automotivo - projetos incentivados (art. 312)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '000005',
+ 'cst': '000',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Operação com EAC destinado à mistura com gasolina A, mas com saída do biocombustível com destinação diversa',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '010001',
+ 'cst': '010',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações do FGTS não realizadas pela Caixa Econômica Federal',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme setorial'},
+ {'anexo': None,
+ 'code': '010002',
+ 'cst': '010',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações do serviço financeiro',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme setorial'},
+ {'anexo': None,
+ 'code': '011001',
+ 'cst': '011',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Planos de assistência funerária.',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme nacional (referência)'},
+ {'anexo': None,
+ 'code': '011002',
+ 'cst': '011',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Planos de assistência à saúde',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme nacional (referência)'},
+ {'anexo': '92401',
+ 'code': '011003',
+ 'cst': '011',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Intermediação de planos de assistência à saúde',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme nacional (referência)'},
+ {'anexo': None,
+ 'code': '011004',
+ 'cst': '011',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Concursos e prognósticos',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme nacional (referência)'},
+ {'anexo': None,
+ 'code': '011005',
+ 'cst': '011',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Planos de assistência à saúde de animais domésticos',
+ 'p_red_cbs': '30',
+ 'p_red_ibs': '30',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme nacional (referência)'},
+ {'anexo': None,
+ 'code': '200001',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Serviços de transporte de bens até as zonas de processamento de exportação e bens exportados a partir das zonas de processamento de exportação',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200002',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento ou importação para produtor rural não contribuinte ou TAC',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '1',
+ 'code': '200003',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Vendas de produtos destinados à alimentação humana (Anexo I)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '12',
+ 'code': '200004',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de dispositivos médicos (Anexo XII)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '4',
+ 'code': '200005',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de dispositivos médicos para órgãos da administração pública e entidades de saúde imunes (Anexo IV)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200006',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Situação de emergência de saúde pública reconhecida pelo Poder público',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '13',
+ 'code': '200007',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos dispositivos de acessibilidade próprios para pessoas com deficiência (Anexo XIII)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '5',
+ 'code': '200008',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos dispositivos de acessibilidade próprios para pessoas com deficiência adquiridos por órgãos da administração pública (Anexo V)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200009',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos medicamentos registrados na Anvisa',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200010',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos medicamentos registrados na Anvisa, adquiridos por órgãos da administração pública',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '6',
+ 'code': '200011',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento das composições para nutrição enteral e parenteral quando adquiridas por órgãos da administração pública (Anexo VI)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200012',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Situação de emergência de saúde pública reconhecida pelo Poder público',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '91471',
+ 'code': '200013',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de tampões higiênicos, absorventes higiênicos internos ou externos',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '15',
+ 'code': '200014',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos produtos hortícolas, frutas e ovos (Anexo XV)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200015',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Venda de automóveis de passageiros de fabricação nacional adquiridos por motoristas profissionais ou pessoas com deficiência',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '91561',
+ 'code': '200016',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Prestação de serviços de pesquisa e desenvolvimento por Instituição Científica, Tecnológica e de Inovação (ICT)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200017',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações relacionadas ao FGTS',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200018',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações de resseguro e retrocessão',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200019',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Importador dos serviços financeiros contribuinte',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200020',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Operação praticada por sociedades cooperativas optantes por regime específico do IBS e CBS',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200021',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Serviços de transporte público coletivo de passageiros ferroviário e hidroviário',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200022',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Operação originada fora da ZFM que destine bem material industrializado a contribuinte estabelecido na ZFM',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200023',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Operação realizada por indústria incentivada que destine bem material intermediário para outra indústria incentivada na ZFM',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200024',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Operação originada fora das Áreas de Livre Comércio destinadas a contribuinte estabelecido nas Áreas de Livre Comércio',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '93081',
+ 'code': '200025',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento dos serviços de educação relacionados ao Programa Universidade para Todos (Prouni)',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '91581',
+ 'code': '200026',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Locação de imóveis localizados nas zonas reabilitadas',
+ 'p_red_cbs': '80',
+ 'p_red_ibs': '80',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '92611',
+ 'code': '200027',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações de locação, cessão onerosa e arrendamento de bens imóveis',
+ 'p_red_cbs': '70',
+ 'p_red_ibs': '70',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '2',
+ 'code': '200028',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento dos serviços de educação (Anexo II)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '3',
+ 'code': '200029',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento dos serviços de saúde humana (Anexo III)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '4',
+ 'code': '200030',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Venda dos dispositivos médicos (Anexo IV)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '5',
+ 'code': '200031',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos dispositivos de acessibilidade próprios para pessoas com deficiência (Anexo V)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200032',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos medicamentos registrados na Anvisa ou produzidos por farmácias de manipulação, ressalvados os medicamentos sujeitos à alíquota zero',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '6',
+ 'code': '200033',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento das composições para nutrição enteral e parenteral (Anexo VI)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '7',
+ 'code': '200034',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos alimentos destinados ao consumo humano (Anexo VII)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '8',
+ 'code': '200035',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos produtos de higiene pessoal e limpeza (Anexo VIII)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200036',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de produtos agropecuários, aquícolas, pesqueiros, florestais e extrativistas vegetais in natura',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200037',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento de serviços ambientais de conservação ou recuperação da vegetação nativa',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '9',
+ 'code': '200038',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos insumos agropecuários e aquícolas (Anexo IX)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '10',
+ 'code': '200039',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento dos bens e serviços relacionados com produções nacionais artísticas, culturais, de eventos, jornalísticas e audiovisuais (Anexo X)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200040',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento de serviços de comunicação institucional à administração pública',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '91411',
+ 'code': '200041',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento de serviço de educação desportiva (art. 141. I)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200042',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento de serviço de gestão e exploração do desporto (art. 141. II)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '11',
+ 'code': '200043',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento à administração pública dos serviços e dos bens relativos à soberania (Anexo XI)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': '11',
+ 'code': '200044',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações e prestações de serviços de segurança da informação e segurança cibernética desenvolvidos por sociedade que tenha sócio brasileiro (Anexo XI)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200045',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações relacionadas a projetos de reabilitação urbana de zonas históricas e de áreas críticas de recuperação e reconversão urbanística',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200046',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações com bens imóveis',
+ 'p_red_cbs': '50',
+ 'p_red_ibs': '50',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None, 'code': '200047', 'cst': '200', 'end': None, 'ind_nfce': True, 'ind_nfe': True, 'name': 'Bares e Restaurantes', 'p_red_cbs': '40', 'p_red_ibs': '40', 'start': '2026-01-01', 'tipo_aliquota': 'Padrão'},
+ {'anexo': '92811',
+ 'code': '200048',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Hotelaria, Parques de Diversão e Parques Temáticos',
+ 'p_red_cbs': '40',
+ 'p_red_ibs': '40',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200049',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Transporte coletivo de passageiros rodoviário, ferroviário e hidroviário',
+ 'p_red_cbs': '40',
+ 'p_red_ibs': '40',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200050',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Serviços de transporte aéreo regional coletivo de passageiros ou de carga',
+ 'p_red_cbs': '40',
+ 'p_red_ibs': '40',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None, 'code': '200051', 'cst': '200', 'end': None, 'ind_nfce': False, 'ind_nfe': False, 'name': 'Agências de Turismo', 'p_red_cbs': '40', 'p_red_ibs': '40', 'start': '2026-01-01', 'tipo_aliquota': 'Padrão'},
+ {'anexo': '91271',
+ 'code': '200052',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Prestação de serviços de profissões intelectuais',
+ 'p_red_cbs': '30',
+ 'p_red_ibs': '30',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200053',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de medicamentos registrados na Anvisa, quando classificados como soros ou vacinas',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '200054',
+ 'cst': '200',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de bem material pela cooperativa de produção agropecuária a associado não sujeito ao regime regular do IBS e da CBS',
+ 'p_red_cbs': '100',
+ 'p_red_ibs': '100',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '220001',
+ 'cst': '220',
+ 'end': '2026-01-01',
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Incorporação imobiliária submetida ao regime especial de tributação',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Fixa'},
+ {'anexo': None,
+ 'code': '220002',
+ 'cst': '220',
+ 'end': '2026-01-01',
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Incorporação imobiliária submetida ao regime especial de tributação',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Fixa'},
+ {'anexo': None,
+ 'code': '220003',
+ 'cst': '220',
+ 'end': '2026-01-01',
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Alienação de imóvel decorrente de parcelamento do solo',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Fixa'},
+ {'anexo': '94871',
+ 'code': '221001',
+ 'cst': '221',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Locação, cessão onerosa ou arrendamento de bem imóvel com alíquota sobre a receita bruta',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Fixa'},
+ {'anexo': None,
+ 'code': '221002',
+ 'cst': '221',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Incorporação imobiliária submetida ao regime especial de tributação',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Fixa'},
+ {'anexo': None,
+ 'code': '221003',
+ 'cst': '221',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Incorporação imobiliária submetida ao regime especial de tributação',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Fixa'},
+ {'anexo': None,
+ 'code': '221004',
+ 'cst': '221',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Alienação de imóvel decorrente de parcelamento do solo',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Fixa'},
+ {'anexo': None,
+ 'code': '222001',
+ 'cst': '222',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Transporte internacional de passageiros, caso os trechos de ida e volta sejam vendidos em conjunto',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '400001',
+ 'cst': '400',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento de serviços de transporte público coletivo de passageiros rodoviário e metroviário',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '400002',
+ 'cst': '400',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento de serviços de transporte público coletivo de passageiros rodoviário e metroviário com medição por quilômetro rodado',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410001',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de bonificações quando constem no documento fiscal e que não dependam de evento posterior',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410002',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Transferências entre estabelecimentos pertencentes ao mesmo contribuinte',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410003',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Doações sem contraprestação em benefício do doador',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410004',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Exportações de bens e serviços',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410005',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimentos realizados pela União, pelos Estados, pelo Distrito Federal e pelos Municípios',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410006',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimentos realizados por entidades religiosas e templos de qualquer culto',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410007',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimentos realizados por partidos políticos, entidades sindicais e instituições de educação e de assistência social',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410008',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimentos de livros, jornais, periódicos e do papel destinado a sua impressão',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410009',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimentos de fonogramas e videofonogramas musicais produzidos no Brasil',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410010',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimentos de serviço de comunicação nas modalidades de radiodifusão sonora e de sons e imagens de recepção livre e gratuita',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410011',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimentos de ouro, quando definido em lei como ativo financeiro ou instrumento cambial',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410012',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de condomínio edilício não optante pelo regime regular',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410013',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Exportações de combustíveis',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410014',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento de produtor rural não contribuinte',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410015',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Fornecimento por transportador autônomo não contribuinte',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410016',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento ou aquisição de resíduos sólidos',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410017',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Aquisição de bem móvel com crédito presumido sob condição de revenda realizada',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410018',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações relacionadas aos fundos garantidores e executores de políticas públicas',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410019',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Exclusão da gorjeta na base de cálculo no fornecimento de alimentação',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410020',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Exclusão do valor de intermediação na base de cálculo no fornecimento de alimentação',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410021',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Contribuição de que trata o art. 149-A da Constituição Federal',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410022',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Consolidação da propriedade do bem pelo credor',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410023',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Alienação de bens móveis ou imóveis que tenham sido objeto de garantia em que o prestador da garantia não seja contribuinte',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410024',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Consolidação da propriedade do bem pelo grupo de consórcio',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410025',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Alienação de bem que tenha sido objeto de garantia em que o prestador da garantia não seja contribuinte',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410026',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Doação com anulação de crédito',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410027',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Exportação de serviço ou de bem imaterial',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410028',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações com bens imóveis realizadas por pessoas físicas não consideradas contribuintes',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410029',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Operações acobertadas somente pelo ICMS',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410030',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Estorno de crédito por perecimento, deteriorização, roubo, furto ou extravio.',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410031',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento em período anterior ao início de vigência de incidências de CBS e IBS',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410032',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Tributos incidentes na operação que não integram a base de cálculo do IBS e da CBS',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410033',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações de Fundos de Investimento Imobiliário (FII) e Fundos de Investimento nas Cadeias Produtivas do Agronegócio (Fiagro)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410034',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Operações de fundos de investimento',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410035',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Fornecimento realizado por nanoempreendedor',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410036',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Descontos incondicionais',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410037',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Importação os bens materiais sem incidência de IBS e CBS',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '410999',
+ 'cst': '410',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Operações não onerosas sem previsão de tributação, não especificadas anteriormente',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': '90281',
+ 'code': '510001',
+ 'cst': '510',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Operações, sujeitas a diferimento, com energia elétrica, relativas à importação, geração, comercialização, distribuição e transmissão',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': '9',
+ 'code': '515001',
+ 'cst': '515',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Operações, sujeitas a diferimento, com insumos agropecuários e aquícolas (Anexo IX)',
+ 'p_red_cbs': '60',
+ 'p_red_ibs': '60',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Padrão'},
+ {'anexo': None,
+ 'code': '550001',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Exportações de bens materiais',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550002',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Regime de Trânsito',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550003',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regimes de Depósito (art. 85)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550004',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regimes de Depósito (art. 87)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550005',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regimes de Depósito (art. 87, Parágrafo único)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550006',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regimes de Permanência Temporária',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550007',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regimes de Aperfeiçoamento',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550008',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Importação de bens para o Regime de Repetro-Temporário',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None, 'code': '550009', 'cst': '550', 'end': None, 'ind_nfce': False, 'ind_nfe': True, 'name': 'GNL-Temporário', 'p_red_cbs': '0', 'p_red_ibs': '0', 'start': '2026-01-01', 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None, 'code': '550010', 'cst': '550', 'end': None, 'ind_nfce': False, 'ind_nfe': True, 'name': 'Repetro-Permanente', 'p_red_cbs': '0', 'p_red_ibs': '0', 'start': '2026-01-01', 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550011',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Repetro-Industrialização',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None, 'code': '550012', 'cst': '550', 'end': None, 'ind_nfce': False, 'ind_nfe': True, 'name': 'Repetro-Nacional', 'p_red_cbs': '0', 'p_red_ibs': '0', 'start': '2026-01-01', 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None, 'code': '550013', 'cst': '550', 'end': None, 'ind_nfce': False, 'ind_nfe': True, 'name': 'Repetro-Entreposto', 'p_red_cbs': '0', 'p_red_ibs': '0', 'start': '2026-01-01', 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550014',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Zona de Processamento de Exportação',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550015',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regime Tributário para Incentivo à Modernização e à Ampliação da Estrutura Portuária',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550016',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regime Especial de Incentivos para o Desenvolvimento da Infraestrutura',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550017',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regime Tributário para Incentivo à Atividade Naval - Renaval (Art. 107, I)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550018',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Desoneração da aquisição de bens de capital',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550019',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Importação de bem material por indústria incentivada para utilização na ZFM',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550020',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Áreas de livre comércio',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550021',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Industrialização destinada a exportações',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550022',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Regime Especial de Incentivos para a Produção de Hidrogênio de Baixa Emissão de Carbono (Rehidro)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550023',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Operações com hidrocarbonetos líquidos derivados de petróleo não combustíveis ou de gás natural, inclusive nafta',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550024',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Regime Tributário para Incentivo à Atividade Naval - Renaval (Art. 107, II)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '550025',
+ 'cst': '550',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Regime Tributário para Incentivo à Atividade Naval - Renaval (Art. 107, III)',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': '91721',
+ 'code': '620001',
+ 'cst': '620',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Tributação monofásica sobre combustíveis',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme setorial'},
+ {'anexo': '91722',
+ 'code': '620002',
+ 'cst': '620',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Tributação monofásica com responsabilidade pela retenção sobre combustíveis',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme setorial'},
+ {'anexo': '91723',
+ 'code': '620003',
+ 'cst': '620',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Tributação monofásica com responsabilidade de retenção de tributos por terceiros',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme setorial'},
+ {'anexo': '91724',
+ 'code': '620004',
+ 'cst': '620',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Tributação monofásica sobre mistura de EAC com gasolina A em percentual superior ao obrigatório',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme setorial'},
+ {'anexo': '91725',
+ 'code': '620005',
+ 'cst': '620',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Tributação monofásica sobre mistura de EAC com gasolina A em percentual inferior ao obrigatório',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme setorial'},
+ {'anexo': '91726',
+ 'code': '620006',
+ 'cst': '620',
+ 'end': None,
+ 'ind_nfce': True,
+ 'ind_nfe': True,
+ 'name': 'Tributação monofásica sobre combustíveis cobrada anteriormente',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Uniforme setorial'},
+ {'anexo': None,
+ 'code': '620007',
+ 'cst': '620',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Perecimento, deteriorização, roubo, furto ou extravio no regime monofásico',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '800001',
+ 'cst': '800',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Fusão, cisão ou incorporação',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '800002',
+ 'cst': '800',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Transferência de crédito do associado, inclusive as cooperativas singulares',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '810001',
+ 'cst': '810',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Crédito presumido de IBS sobre o valor apurado nos fornecimentos a partir da ZFM',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '811001',
+ 'cst': '811',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Anulação de Crédito por Saídas Imunes/Isentas',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '811002',
+ 'cst': '811',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Débitos de notas fiscais não processadas na apuração',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '811003',
+ 'cst': '811',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Desenquadramento do Simples Nacional',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': '92341',
+ 'code': '820001',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Documento com informações de fornecimento de serviços de planos de assistência à saúde elencados no art. 234 da Lei Complementar nº214, de 2025',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': '92361',
+ 'code': '820002',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Documento com informações de fornecimento de serviços de planos de assistência funerária',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': '92431',
+ 'code': '820003',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Documento com informações de fornecimento de serviços de planos de assistência à saúde de animais domésticos',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '820004',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Documento com informações de prestação de serviços de consursos de prognósticos',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '820005',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Documento com informações de alienação de bens imóveis',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': '90111',
+ 'code': '820006',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Documento com informações de fornecimento de serviços de exploração de via',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': '91811',
+ 'code': '820007',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Documento com informações de fornecimento de serviços financeiros',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '820008',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Documento com informações de fornecimento de serviço continuado, mas com tributação realizada em fatura anterior',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '820009',
+ 'cst': '820',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': False,
+ 'name': 'Cobrança relativa a fornecimentos declarados em outro documento',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'},
+ {'anexo': None,
+ 'code': '830001',
+ 'cst': '830',
+ 'end': None,
+ 'ind_nfce': False,
+ 'ind_nfe': True,
+ 'name': 'Documento com exclusão da BC da CBS e do IBS de energia elétrica fornecida pela distribuidora à UC',
+ 'p_red_cbs': '0',
+ 'p_red_ibs': '0',
+ 'start': '2026-01-01',
+ 'tipo_aliquota': 'Sem alíquota'}]
+
+LC214_SOURCE = {'accessed_at': '2026-09-24',
+ 'document': 'Lei Complementar 214/2025 compiled (through LC 227/2026)',
+ 'fetched_via': 'Internet Archive copy of the official URL',
+ 'sha256': '5c7d59b3c49e5b7c066c2ad28bedf32791193a676ec1a163bec14bea5fa2f680',
+ 'url': 'https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp214.htm'}
+
+LC214_ANNEXES = {'I': {'items': [{'clean': True, 'description': 'Arroz das subposições 1006.20 e 1006.30 e do código 1006.40.00 da NCM/SH', 'item': 1, 'prefixes': ['100620', '100630', '10064000']},
+ {'clean': False,
+ 'description': 'Leite, em conformidade com os requisitos da legislação específica relativos ao consumo direto pela população, classificado nos códigos 0401.10.10, 0401.10.90, 0401.20.10, 0401.20.90, '
+ '0401.40.10 e 0401.50.10 da NCM/SH',
+ 'item': 2,
+ 'prefixes': ['04011010', '04011090', '04012010', '04012090', '04014010', '04015010']},
+ {'clean': False,
+ 'description': 'Leite em pó, em conformidade com os requisitos da legislação específica, classificado nos códigos 0402.10.10, 0402.10.90, 0402.21.10, 0402.21.20, 0402.29.10 e 0402.29.20 da NCM/SH',
+ 'item': 3,
+ 'prefixes': ['04021010', '04021090', '04022110', '04022120', '04022910', '04022920']},
+ {'clean': False,
+ 'description': 'Fórmulas infantis, em conformidade com os requisitos da legislação específica, classificadas nos códigos 1901.10.10, 1901.10.90 e 2106.90.90 da NCM/SH',
+ 'item': 4,
+ 'prefixes': ['19011010', '19011090', '21069090']},
+ {'clean': True, 'description': 'Manteiga do código 0405.10.00 da NCM/SH', 'item': 5, 'prefixes': ['04051000']},
+ {'clean': True, 'description': 'Margarina do código 1517.10.00 da NCM/SH', 'item': 6, 'prefixes': ['15171000']},
+ {'clean': True, 'description': 'Feijões dos códigos 0713.33.19, 0713.33.29, 0713.33.99 e 0713.35.90 da NCM/SH', 'item': 7, 'prefixes': ['07133319', '07133329', '07133399', '07133590']},
+ {'clean': True, 'description': 'Café da posição 09.01 e da subposição 2101.1, ambos da NCM/SH', 'item': 8, 'prefixes': ['0901', '21011']},
+ {'clean': False,
+ 'description': 'Óleo de babaçu do código 1513.21.20 da NCM/SH, em conformidade com os requisitos da legislação específica relativos ao consumo como alimento',
+ 'item': 9,
+ 'prefixes': ['15132120']},
+ {'clean': True,
+ 'description': 'Farinha de mandioca classificada no código 1106.20.00 da NCM/SH e tapioca e seus sucedâneos do código 1903.00.00 da NCM/SH',
+ 'item': 10,
+ 'prefixes': ['11062000', '19030000']},
+ {'clean': True, 'description': 'Farinha, grumos e sêmolas, de milho, dos códigos 1102.20.00 e 1103.13.00 da NCM', 'item': 11, 'prefixes': ['11022000', '11031300']},
+ {'clean': True, 'description': 'Grãos de milho classificados no código 1104.19.00 e do código 1104.23.00 da NCM/SH', 'item': 12, 'prefixes': ['11041900', '11042300']},
+ {'clean': True, 'description': 'Farinha de trigo do código 1101.00.10 da NCM/SH', 'item': 13, 'prefixes': ['11010010']},
+ {'clean': True, 'description': 'Açúcar classificado nos códigos 1701.14.00 e 1701.99.00 da NCM/SH', 'item': 14, 'prefixes': ['17011400', '17019900']},
+ {'clean': True, 'description': 'Massas alimentícias da subposição 1902.1 da NCM/SH', 'item': 15, 'prefixes': ['19021']},
+ {'clean': False,
+ 'description': 'Pão comumente denominado pão francês, de formato cilíndrico e alongado, com miolo branco creme e macio, e casca dourada e crocante, elaborado a partir da mistura ou pré-mistura de '
+ 'farinha de trigo, fermento biológico, água, sal, açúcar, aditivos alimentares e produtos de fortificação de farinhas, em conformidade com a legislação vigente, classificado no código '
+ '1905.90.90 da NCM/SH e a pré-mistura ',
+ 'item': 16,
+ 'prefixes': ['19012010', '19012090', '19059090']},
+ {'clean': True, 'description': 'Grãos de aveia dos códigos 1104.12.00 e 1104.22.00 da NCM/SH', 'item': 17, 'prefixes': ['11041200', '11042200']},
+ {'clean': True, 'description': 'Farinha de aveia classificada no código 1102.90.00 da NCM/SH', 'item': 18, 'prefixes': ['11029000']},
+ {'clean': False,
+ 'description': 'Carnes bovina, suína, ovina, caprina e de aves e produtos de origem animal (exceto foies gras ) dos seguintes códigos, subposições e posições da NCM/SH: a) 02.01, 02.02, 0206.10.00, '
+ '0206.2 e 0210.20.00; b) 02.03, 0206.30.00, 0206.4, 0209.10 e 0210.1; c) 02.04 e 0210.99.20, carne caprina classificada no código 0210.99.90 e miudezas comestíveis de ovinos e caprinos '
+ 'classificadas nos códigos 0206.80.',
+ 'item': 19,
+ 'prefixes': ['0201',
+ '0202',
+ '0203',
+ '0204',
+ '02061000',
+ '02062',
+ '02063000',
+ '02064',
+ '02068000',
+ '02069000',
+ '0207',
+ '02074300',
+ '02075300',
+ '020910',
+ '02099000',
+ '02101',
+ '02102000',
+ '0210991',
+ '02109920',
+ '02109990']},
+ {'clean': False,
+ 'description': 'Peixes e carnes de peixes (exceto salmonídeos, atuns, bacalhaus, hadoque, saithe e ovas e outros subprodutos) dos seguintes códigos, subposições e posições da NCM/SH: a) 03.02; exceto '
+ 'os produtos das subposições e dos códigos 0302.1, 0302.3, 0302.51.00, 0302.52.00, 0302.53.00 e 0302.9 da NCM/SH; b) 03.03; exceto os produtos das subposições e dos códigos 0303.1, '
+ '0303.4, 0303.63.00, 0303.64.00, 0303',
+ 'item': 20,
+ 'prefixes': ['0302',
+ '03021',
+ '03023',
+ '03025100',
+ '03025200',
+ '03025300',
+ '03029',
+ '0303',
+ '03031',
+ '03034',
+ '03036300',
+ '03036400',
+ '03036500',
+ '03039',
+ '0304',
+ '03044',
+ '03045',
+ '03047',
+ '03048',
+ '03049']},
+ {'clean': False,
+ 'description': 'Queijos tipo mozarela, minas, prato, queijo de coalho, ricota, requeijão, queijo provolone, queijo parmesão, queijo fresco não maturado e queijo do reino classificados nos códigos '
+ '0406.10.10, 0406.10.90, 0406.20.00, 0406.90.10, 0406.90.20 e 0406.90.30 da NCM/SH',
+ 'item': 21,
+ 'prefixes': ['04061010', '04061090', '04062000', '04069010', '04069020', '04069030']},
+ {'clean': False,
+ 'description': 'Sal em conformidade com os requisitos da legislação específica relativos ao teor de iodo enquadrado nos limites próprios para consumo humano classificado nos códigos 2501.00.20 e '
+ '2501.00.90 da NCM/SH',
+ 'item': 22,
+ 'prefixes': ['25010020', '25010090']},
+ {'clean': True, 'description': 'Mate da posição 09.03 da NCM/SH', 'item': 23, 'prefixes': ['0903']},
+ {'clean': True, 'description': 'Farinha com baixo teor de proteína para pessoas com aminoacidopatias, acidemias e defeitos do ciclo da uréia da NCM 1901.90.90', 'item': 24, 'prefixes': ['19019090']},
+ {'clean': True, 'description': 'Massas com baixo teor de proteína para pessoas com aminoacidopatias, acidemias e defeitos do ciclo da uréia da NCM 1902.19.00', 'item': 25, 'prefixes': ['19021900']},
+ {'clean': False, 'description': 'Fórmulas Dietoterápicas para Erros Inatos do Metabolismo da NCM 2106.9090', 'item': 26, 'prefixes': []}],
+ 'number': 1,
+ 'revoked': False,
+ 'title': 'ANEXO I PRODUTOS DESTINADOS À ALIMENTAÇÃO HUMANA SUBMETIDOS À REDUÇÃO A ZERO DAS ALÍQUOTAS DO IBS E DA CBS (EXCLUSIVE PRODUTOS HORTÍCOLAS, FRUTAS E OVOS, RELACIONADOS NO ANEXO XV) ITEM DESCRIÇÃO DO PR'},
+ 'II': {'items': [{'clean': True, 'description': 'Ensino Infantil, inclusive creche e pré-escola 1.2201.1', 'item': 1, 'prefixes': ['22011']},
+ {'clean': True, 'description': 'Ensino Fundamental 1.2201.20.00', 'item': 2, 'prefixes': ['22012000']},
+ {'clean': True, 'description': 'Ensino Médio 1.2201.30.00', 'item': 3, 'prefixes': ['22013000']},
+ {'clean': True, 'description': 'Ensino Técnico de Nível Médio 1.2202.00.00', 'item': 4, 'prefixes': ['22020000']},
+ {'clean': False,
+ 'description': 'Ensino para jovens e adultos destinado àqueles que não tiveram acesso ou continuidade de estudos no ensino fundamental e médio na idade própria 1.2203',
+ 'item': 5,
+ 'prefixes': []},
+ {'clean': False, 'description': 'Ensino Superior, compreendidos os cursos e programas de graduação, pós-graduação, de extensão e cursos sequenciais 1.2204', 'item': 6, 'prefixes': []},
+ {'clean': True, 'description': 'Ensino de sistemas linguísticos de natureza visomotora e de escrita tátil 1.2205.13.00', 'item': 7, 'prefixes': ['22051300']},
+ {'clean': True, 'description': 'Ensino de línguas nativas de povos originários 1.2205.13.00', 'item': 8, 'prefixes': ['22051300']},
+ {'clean': False,
+ 'description': 'Educação especial destinada a pessoas com deficiência, transtornos globais do desenvolvimento e altas habilidades ou superdotação, de modo isolado ou agregado a qualquer das etapas de '
+ 'educação tratadas neste Anexo',
+ 'item': 9,
+ 'prefixes': []}],
+ 'number': 2,
+ 'revoked': False,
+ 'title': 'ANEXO II SERVIÇOS DE EDUCAÇÃO SUBMETIDOS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO DO SERVIÇO NBS 1 Ensino Infantil, inclusive creche e pré-escola 1.2201.1 2 '
+ 'E'},
+ 'III': {'items': [{'clean': True, 'description': 'Serviços cirúrgicos 1.2301.11.00', 'item': 1, 'prefixes': ['23011100']},
+ {'clean': True, 'description': 'Serviços ginecológicos e obstétricos 1.2301.12.00', 'item': 2, 'prefixes': ['23011200']},
+ {'clean': True, 'description': 'Serviços psiquiátricos 1.2301.13.00', 'item': 3, 'prefixes': ['23011300']},
+ {'clean': True, 'description': 'Serviços prestados em Unidades de Terapia Intensiva 1.2301.14.00', 'item': 4, 'prefixes': ['23011400']},
+ {'clean': True, 'description': 'Serviços de atendimento de urgência 1.2301.15.00', 'item': 5, 'prefixes': ['23011500']},
+ {'clean': False, 'description': 'Serviços hospitalares não classificados em subposições anteriores 1.2301.19.00', 'item': 6, 'prefixes': ['23011900']},
+ {'clean': True, 'description': 'Serviços de clínica médica 1.2301.21.00', 'item': 7, 'prefixes': ['23012100']},
+ {'clean': True, 'description': 'Serviços médicos especializados 1.2301.22.00', 'item': 8, 'prefixes': ['23012200']},
+ {'clean': True, 'description': 'Serviços odontológicos 1.2301.23.00', 'item': 9, 'prefixes': ['23012300']},
+ {'clean': True, 'description': 'Serviços de enfermagem 1.2301.91.00', 'item': 10, 'prefixes': ['23019100']},
+ {'clean': True, 'description': 'Serviços de fisioterapia 1.2301.92.00', 'item': 11, 'prefixes': ['23019200']},
+ {'clean': True, 'description': 'Serviços laboratoriais 1.2301.93.00', 'item': 12, 'prefixes': ['23019300']},
+ {'clean': True, 'description': 'Serviços de diagnóstico por imagem 1.2301.94.00', 'item': 13, 'prefixes': ['23019400']},
+ {'clean': True, 'description': 'Serviços de bancos de material biológico humano 1.2301.95.00', 'item': 14, 'prefixes': ['23019500']},
+ {'clean': True, 'description': 'Serviços de ambulância 1.2301.96.00', 'item': 15, 'prefixes': ['23019600']},
+ {'clean': True, 'description': 'Serviços de assistência ao parto e pós-parto 1.2301.97.00', 'item': 16, 'prefixes': ['23019700']},
+ {'clean': True, 'description': 'Serviços de psicologia 1.2301.98.00', 'item': 17, 'prefixes': ['23019800']},
+ {'clean': True, 'description': 'Serviços de vigilância sanitária 1.2301.99.00', 'item': 18, 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços de epidemiologia 1.2301.99.00', 'item': 19, 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços de vacinação 1.2301.99.00', 'item': 20, 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços de fonoaudiologia 1.2301.99.00', 'item': 21, 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços de nutrição 1.2301.99.00', 'item': 22, 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços de optometria 1.2301.99.00', 'item': 23, 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços de instrumentação cirúrgica 1.2301.99.00', 'item': 24, 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços de biomedicina 1.2301.99.00', 'item': 25, 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços farmacêuticos 1.2301.99.00', 'item': 26, 'prefixes': ['23019900']},
+ {'clean': False, 'description': 'Serviços de cuidado e assistência a idosos e pessoas com deficiência em unidades de acolhimento 1.2302', 'item': 27, 'prefixes': []},
+ {'clean': True,
+ 'description': 'Serviços domiciliares de apoio a pessoas adultas, idosas, crianças, adolescentes, pessoas com transtornos mentais e com deficiências 1.2301.99.00',
+ 'item': 28,
+ 'prefixes': ['23019900']},
+ {'clean': True, 'description': 'Serviços de esterilização 1.2301.99.0', 'item': 29, 'prefixes': ['2301990']},
+ {'clean': True, 'description': 'Serviços funerários, de cremação e de embalsamamento 1.2603.00.00', 'item': 30, 'prefixes': ['26030000']}],
+ 'number': 3,
+ 'revoked': False,
+ 'title': 'ANEXO III SERVIÇOS DE SAÚDE SUBMETIDOS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO DO SERVIÇO NBS 1 Serviços cirúrgicos 1.2301.11.00 2 Serviços ginecológicos e '
+ 'o'},
+ 'IV': {'items': [{'clean': True, 'description': 'Bolsa para drenagem 3926.90.30', 'item': 1, 'prefixes': ['39269030']},
+ {'clean': True, 'description': 'Sistema para drenagem com conjunto intermediário para medição contínua da diurese 9018.90.99', 'item': 2, 'prefixes': ['90189099']},
+ {'clean': True, 'description': 'Chapas e filmes para raios-X, sensibilizados em uma face 3701.10.10', 'item': 3, 'prefixes': ['37011010']},
+ {'clean': True, 'description': 'Cimentos para reconstituição óssea 3006.40.20', 'item': 4, 'prefixes': ['30064020']},
+ {'clean': True, 'description': 'Substitutos de enxerto ósseo 3004.90.99', 'item': 5, 'prefixes': ['30049099']},
+ {'clean': True, 'description': 'Coletor para unidade de drenagem externa 3926.90.40', 'item': 6, 'prefixes': ['39269040']},
+ {'clean': True, 'description': 'Conector completo com tampa 3917.40', 'item': 7, 'prefixes': ['391740']},
+ {'clean': True, 'description': 'Conector em Y 3917.40', 'item': 8, 'prefixes': ['391740']},
+ {'clean': True, 'description': 'Conjuntos de troca e concentrados polieletrolíticos para diálise 3004.90.99', 'item': 9, 'prefixes': ['30049099']},
+ {'clean': True, 'description': 'Conjunto para autotransfusão 9018.90.10', 'item': 10, 'prefixes': ['90189010']},
+ {'clean': True, 'description': 'Conjunto para hidrocefalia de baixo perfil 9021.90.19', 'item': 11, 'prefixes': ['90219019']},
+ {'clean': True, 'description': 'Conjunto para hidrocefalia standard 9021.90.19 9021.90.80', 'item': 12, 'prefixes': ['90219019', '90219080']},
+ {'clean': True, 'description': 'Eletrodo endocárdico definitivo 9021.90.91', 'item': 13, 'prefixes': ['90219091']},
+ {'clean': True, 'description': 'Eletrodo epicárdico definitivo 9021.90.91', 'item': 14, 'prefixes': ['90219091']},
+ {'clean': True, 'description': 'Eletrodo para marcapasso temporário endocárdico 9021.90.91', 'item': 15, 'prefixes': ['90219091']},
+ {'clean': True, 'description': 'Eletrodo para marcapasso temporário epicárdico 9021.90.91', 'item': 16, 'prefixes': ['90219091']},
+ {'clean': True, 'description': 'Espaçador de tendão 9021.90.19', 'item': 17, 'prefixes': ['90219019']},
+ {'clean': True, 'description': 'Filmes especiais para raios-X sensibilizados em ambas as faces 3702.10.20', 'item': 18, 'prefixes': ['37021020']},
+ {'clean': True, 'description': 'Filmes especiais para raios-X sensibilizados em uma face 3702.10.10', 'item': 19, 'prefixes': ['37021010']},
+ {'clean': True, 'description': 'Filtro de linha arterial e venoso 8421.29.90', 'item': 20, 'prefixes': ['84212990']},
+ {'clean': True, 'description': 'Filtro de sangue arterial e venoso para recirculação 8421.29.90', 'item': 21, 'prefixes': ['84212990']},
+ {'clean': True, 'description': 'Filtro para cardioplegia 8421.29.90', 'item': 22, 'prefixes': ['84212990']},
+ {'clean': False,
+ 'description': 'Categutes esterilizados, materiais esterilizados semelhantes para suturas cirúrgicas (incluídos os fios absorvíveis esterilizados para cirurgia ou odontologia) e adesivos '
+ 'esterilizados para tecidos orgânicos, utilizados em cirurgia para fechar ferimentos; laminárias esterilizadas; hemostáticos absorvíveis esterilizados para cirurgia ou odontologia; '
+ 'barreiras antiaderentes esterilizadas para cirurg',
+ 'item': 23,
+ 'prefixes': ['300610']},
+ {'clean': True, 'description': 'Hemoconcentrador para circulação extracorpórea 9018.90.40', 'item': 24, 'prefixes': ['90189040']},
+ {'clean': True, 'description': 'Hemodialisador capilar 8421.29.11', 'item': 25, 'prefixes': ['84212911']},
+ {'clean': True, 'description': 'Marcapasso cardíaco câmara dupla 9021.50.00', 'item': 26, 'prefixes': ['90215000']},
+ {'clean': True, 'description': 'Marcapasso cardíaco multiprogramável com telemetria 9021.50.00', 'item': 27, 'prefixes': ['90215000']},
+ {'clean': True, 'description': 'Outras chapas e filmes para raios-X 3701.10.29', 'item': 28, 'prefixes': ['37011029']},
+ {'clean': True, 'description': 'Oxigenador de bolha com tubos para circulação extracorpórea 9018.90.99', 'item': 29, 'prefixes': ['90189099']},
+ {'clean': True, 'description': 'Oxigenador de membrana com tubos para circulação extracorpórea 9018.90.99', 'item': 30, 'prefixes': ['90189099']},
+ {'clean': True, 'description': 'Reservatório de cardiotomia 9018.90.99', 'item': 31, 'prefixes': ['90189099']},
+ {'clean': True, 'description': 'Reservatório para cardioplegia com tubo sem filtro 9018.90.99', 'item': 32, 'prefixes': ['90189099']},
+ {'clean': True, 'description': 'Rins artificiais 9018.90.40', 'item': 33, 'prefixes': ['90189040']},
+ {'clean': True, 'description': 'Shunt lombo-peritonal 9021.90.19', 'item': 34, 'prefixes': ['90219019']},
+ {'clean': True, 'description': 'Substituto temporário de pele (biológica/sintética) (por cm2) 3005.90.90', 'item': 35, 'prefixes': ['30059090']},
+ {'clean': True, 'description': 'Tela inorgânica 3006.10.90', 'item': 36, 'prefixes': ['30061090']},
+ {'clean': True, 'description': 'Válvula para hidrocefalia 9021.90.19 9021.90.89', 'item': 37, 'prefixes': ['90219019', '90219089']},
+ {'clean': True, 'description': 'Válvula para tratamento de ascite 9021.90.19', 'item': 38, 'prefixes': ['90219019']},
+ {'clean': True, 'description': 'Fonte de irídio 192 2844.43.90', 'item': 39, 'prefixes': ['28444390']},
+ {'clean': True, 'description': 'Stent vascular 9021.90.12', 'item': 40, 'prefixes': ['90219012']},
+ {'clean': True, 'description': 'Reprocessador de filtros utilizados em hemodiálise 8479.89.99', 'item': 41, 'prefixes': ['84798999']},
+ {'clean': True,
+ 'description': 'Implantes osseointegráveis, na forma de parafuso, e seus componentes manufaturados, tais como tampas de proteção, montadores, conjuntos, pilares (cicatrizador, conector, de '
+ 'transferência ou temporário), cilindros, seus acessórios, destinados a sustentar, amparar, acoplar ou fixar próteses dentárias 9021.29.00 9021.10.10 9021.10.20',
+ 'item': 42,
+ 'prefixes': ['90211010', '90211020', '90212900']},
+ {'clean': True, 'description': 'Cardiodesfibrilador implantável 9021.90.11', 'item': 43, 'prefixes': ['90219011']},
+ {'clean': True, 'description': 'Espiral para embolização 9021.90.12', 'item': 44, 'prefixes': ['90219012']},
+ {'clean': True, 'description': 'Imunoglobulina anti-Rh 3002.12.21', 'item': 45, 'prefixes': ['30021221']},
+ {'clean': True, 'description': 'Outras imunoglobulinas séricas 3002.12.22', 'item': 46, 'prefixes': ['30021222']},
+ {'clean': True, 'description': 'Concentrado de fator VIII 3002.12.23', 'item': 47, 'prefixes': ['30021223']},
+ {'clean': False,
+ 'description': 'Outras frações do sangue, exceto as preparadas como medicamentos, as imunoglobulinas séricas, o concentrado de fator VIII e a soroalbumina sob a forma de gel para preparação de '
+ 'reagentes de diagnóstico 3002.12.21 3002.12.29',
+ 'item': 48,
+ 'prefixes': ['30021221', '30021229']},
+ {'clean': False,
+ 'description': 'Reagentes de diagnóstico ou de laboratório em qualquer suporte e reagentes de diagnóstico ou de laboratório preparados, mesmo em um suporte, mesmo apresentados sob a forma de estojos, '
+ 'exceto os da posição 30.06; materiais de referência certificados 3822.1',
+ 'item': 49,
+ 'prefixes': ['3006', '38221']},
+ {'clean': True, 'description': 'Reagentes de diagnóstico concebidos para serem administrados ao paciente, à base de somatoliberina 3006.30.21', 'item': 50, 'prefixes': ['30063021']},
+ {'clean': False, 'description': 'Produtos para obturação dentária, exceto cimentos 3006.40.12', 'item': 51, 'prefixes': ['30064012']},
+ {'clean': True,
+ 'description': 'Preparações em gel, concebidas para uso em medicina humana ou veterinária como lubrificante para certas partes do corpo em intervenções cirúrgicas ou exames médicos ou como agente de '
+ 'ligação entre o corpo e os instrumentos médicos 3006.70.00',
+ 'item': 52,
+ 'prefixes': ['30067000']},
+ {'clean': True, 'description': 'Bolsas para uso em colostomia, ileostomia e urostomia 3006.91.10', 'item': 53, 'prefixes': ['30069110']},
+ {'clean': False, 'description': 'Equipamentos identificáveis para ostomia, exceto bolsas para uso em colostomia, ileostomia e urostomia 3006.91.90', 'item': 54, 'prefixes': ['30069190']},
+ {'clean': True, 'description': 'Bolsas para uso em medicina (hemodiálise e usos semelhantes) 3926.90.30', 'item': 55, 'prefixes': ['39269030']},
+ {'clean': False, 'description': 'Artigos exclusivamente de laboratório de análises clínicas 3926.90.40', 'item': 56, 'prefixes': ['39269040']},
+ {'clean': True,
+ 'description': 'Acessórios de plástico do tipo utilizado em linhas de sangue para hemodiálise, tais como: obturadores, incluídos os reguláveis ( clamps ) , clipes e similares 3926.90.50',
+ 'item': 57,
+ 'prefixes': ['39269050']},
+ {'clean': True, 'description': 'Luvas cirúrgicas e luvas de procedimento 4015.1', 'item': 58, 'prefixes': ['40151']},
+ {'clean': True, 'description': 'Seringas, mesmo com agulhas 9018.31', 'item': 59, 'prefixes': ['901831']},
+ {'clean': True, 'description': 'Agulhas tubulares de metal e agulhas para suturas 9018.32', 'item': 60, 'prefixes': ['901832']},
+ {'clean': False, 'description': 'Agulhas, exceto as de metal e as para suturas 9018.39.10', 'item': 61, 'prefixes': ['90183910']},
+ {'clean': True, 'description': 'Sondas, cateteres e cânulas, individualmente ou em conjunto 9018.39.2', 'item': 62, 'prefixes': ['9018392']},
+ {'clean': True, 'description': 'Lancetas para vacinação e cautérios 9018.39.30', 'item': 63, 'prefixes': ['90183930']},
+ {'clean': True, 'description': 'Instrumentos semelhantes a seringas, a agulhas, a cateteres e a cânulas 9018.39.9', 'item': 64, 'prefixes': ['9018399']},
+ {'clean': True, 'description': 'Brocas para odontologia 9018.49.1', 'item': 65, 'prefixes': ['9018491']},
+ {'clean': True, 'description': 'Limas 9018.49.20', 'item': 66, 'prefixes': ['90184920']},
+ {'clean': True, 'description': 'Grampos e clipes, seus aplicadores e extratores 9018.90.95', 'item': 67, 'prefixes': ['90189095']},
+ {'clean': True,
+ 'description': 'Outros instrumentos e aparelhos para medicina, cirurgia e odontologia, excluídas seringas e agulhas, das posições 9018.31 e 9018.32 9018.39.99 9018.90.99',
+ 'item': 68,
+ 'prefixes': ['901831', '901832', '90183999', '90189099']},
+ {'clean': True, 'description': 'Mesas de operação e para exames, camas hospitalares e de uso clínico 9402.90', 'item': 69, 'prefixes': ['940290']},
+ {'clean': True, 'description': 'Fotocoagulador a laser 9018.20.10', 'item': 70, 'prefixes': ['90182010']},
+ {'clean': True, 'description': 'Bisturi elétrico 9018.90.21', 'item': 71, 'prefixes': ['90189021']},
+ {'clean': True, 'description': 'Aparelho de anestesia com monitor multiparâmetros 9018.90.99', 'item': 72, 'prefixes': ['90189099']},
+ {'clean': True, 'description': 'Autoclave 8419.81.10', 'item': 73, 'prefixes': ['84198110']},
+ {'clean': True, 'description': 'Retinógrafo 9018.50.90', 'item': 74, 'prefixes': ['90185090']},
+ {'clean': True, 'description': 'Meios de cultura 3821.00.00', 'item': 75, 'prefixes': ['38210000']},
+ {'clean': True, 'description': 'Termocicladores utilizados em diagnóstico e na pesquisa científica 8419.89.99', 'item': 76, 'prefixes': ['84198999']},
+ {'clean': True, 'description': 'Partes e peças de termocicladores 8419.90.40', 'item': 77, 'prefixes': ['84199040']},
+ {'clean': True, 'description': 'Pipetadores laboratoriais para diagnóstico e pesquisa científica 8479.89.12', 'item': 78, 'prefixes': ['84798912']},
+ {'clean': True, 'description': 'Cromatógrafo de fase líquida 9027.20.12', 'item': 79, 'prefixes': ['90272012']},
+ {'clean': True, 'description': 'Sequenciadores automáticos de ADN mediante eletroforese capilar 9027.20.21', 'item': 80, 'prefixes': ['90272021']},
+ {'clean': True, 'description': 'Aparelhos de eletroforese para diagnóstico e pesquisa científica 9027.20.29', 'item': 81, 'prefixes': ['90272029']},
+ {'clean': True, 'description': 'Analisadores por espectrofotometria para diagnóstico e pesquisa científica 9027.30', 'item': 82, 'prefixes': ['902730']},
+ {'clean': True, 'description': 'Analisadores por fotometria para diagnóstico e pesquisa científica 9027.50.20', 'item': 83, 'prefixes': ['90275020']},
+ {'clean': True, 'description': 'Citômetro de fluxo 9027.50.50', 'item': 84, 'prefixes': ['90275050']},
+ {'clean': True, 'description': 'Analisadores por radiações ópticas para diagnóstico e pesquisa científica 9027.50.90', 'item': 85, 'prefixes': ['90275090']},
+ {'clean': True, 'description': 'Outros analisadores para diagnóstico e pesquisa científica 9027.89.99', 'item': 86, 'prefixes': ['90278999']},
+ {'clean': True, 'description': 'Espectrômetro de massa 9027.81.00', 'item': 87, 'prefixes': ['90278100']},
+ {'clean': True, 'description': 'Outros analisadores para diagnóstico 9027.89.99', 'item': 88, 'prefixes': ['90278999']},
+ {'clean': True, 'description': 'Micrótomo 9027.90.10', 'item': 89, 'prefixes': ['90279010']},
+ {'clean': True, 'description': 'Partes e peças de equipamentos analisadores laboratoriais 9027.90.9', 'item': 90, 'prefixes': ['9027909']},
+ {'clean': True, 'description': 'Preservativo 4014.10.00', 'item': 91, 'prefixes': ['40141000']},
+ {'clean': True, 'description': 'Dispositivo intrauterino (DIU) 9018.90.99', 'item': 92, 'prefixes': ['90189099']},
+ {'clean': True, 'description': 'Substância para conservação de órgãos e tecidos 3824.99.89', 'item': 93, 'prefixes': ['38249989']},
+ {'clean': True, 'description': 'Introdutor de punção para implante de eletrodo endocárdico 9021.90.91', 'item': 94, 'prefixes': ['90219091']},
+ {'clean': True, 'description': 'Enxerto tubular de politetrafluoretileno - PTFE (por cm2) 9021.90.99', 'item': 95, 'prefixes': ['90219099']},
+ {'clean': True, 'description': 'Enxerto arterial e venoso tubular inorgânico 9021.90.99', 'item': 96, 'prefixes': ['90219099']},
+ {'clean': True, 'description': 'Botão para crânio 9021.90.99', 'item': 97, 'prefixes': ['90219099']},
+ {'clean': True, 'description': 'Guia metálico para introdução de cateter duplo lumen 9018.39.29', 'item': 98, 'prefixes': ['90183929']},
+ {'clean': True, 'description': 'Dilatador para implante de cateter duplo lumen 9018.39.29', 'item': 99, 'prefixes': ['90183929']},
+ {'clean': True, 'description': 'Guia de troca para angioplastia 9018.39.29', 'item': 100, 'prefixes': ['90183929']},
+ {'clean': True, 'description': 'Introdutor para cateter com e sem válvula 9018.39.29', 'item': 101, 'prefixes': ['90183929']},
+ {'clean': True, 'description': 'Kit cânula 9018.39.99 9018.39.91', 'item': 102, 'prefixes': ['90183991', '90183999']},
+ {'clean': True, 'description': 'Dreno para sucção 9018.39.29', 'item': 103, 'prefixes': ['90183929']},
+ {'clean': True, 'description': 'Sistema de drenagem mediastinal 9018.39.29', 'item': 104, 'prefixes': ['90183929']},
+ {'clean': True, 'description': 'Conjunto descartável de balão intra-aórtico 9018.90.99', 'item': 105, 'prefixes': ['90189099']}],
+ 'number': 4,
+ 'revoked': False,
+ 'title': 'ANEXO IV DISPOSITIVOS MÉDICOS SUBMETIDOS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO NCM/SH 1 Bolsa para drenagem 3926.90.30 2 Sistema para drenagem com '
+ 'conjunto'},
+ 'IX': {'items': [{'clean': False, 'description': 'Biofertilizantes, em conformidade com as definições e demais requisitos da legislação específica 3101.00.00', 'item': 1, 'prefixes': ['31010000']},
+ {'clean': False,
+ 'description': 'Fertilizantes (adubos), em conformidade com as definições e demais requisitos da legislação específica Capítulo 31 3824.99.77 3824.99.79 3824.99.89',
+ 'item': 2,
+ 'prefixes': ['38249977', '38249979', '38249989']},
+ {'clean': False,
+ 'description': 'Corretivos de solo (inclusive condicionadores), remineralizadores e substratos para plantas; em conformidade com as definições e demais requisitos da legislação específica Capítulo 25',
+ 'item': 3,
+ 'prefixes': []},
+ {'clean': False,
+ 'description': 'Inoculantes, meios de cultura e outros microorganismos para uso agrícola; em conformidade com as definições e demais requisitos da legislação específica 3002.49 3002.90.00 3821.00.00',
+ 'item': 4,
+ 'prefixes': ['300249', '30029000', '38210000']},
+ {'clean': False,
+ 'description': 'Bioestimulantes e bioinsumos para controle fitossanitário, em conformidade com as definições e demais requisitos da legislação específica 38.24 3807.00.00 12.11 38.08',
+ 'item': 5,
+ 'prefixes': ['1211', '38070000', '3808', '3824']},
+ {'clean': False,
+ 'description': 'Inseticidas, fungicidas, formicidas, herbicidas, parasiticidas, germicidas, acaricidas, nematicidas, raticidas, desfolhantes, dessecantes, espalhantes adesivos, estimuladores e '
+ 'inibidores de crescimento (reguladores); todos destinados diretamente ao uso agropecuário ou destinados diretamente à fabricação de defensivo agropecuário; em conformidade com as '
+ 'definições e demais requisitos da legislação',
+ 'item': 6,
+ 'prefixes': ['3808', '38249989']},
+ {'clean': False,
+ 'description': 'Calcário, casca de coco triturada, turfa; tortas, bagaços e demais resíduos e desperdícios vegetais das indústrias alimentares; cascas, serragens e demais resíduos e desperdícios de '
+ 'madeira; resíduos da indústria de celulose (dregs e grits), ossos, borra de carnaúba, cinzas, resíduos agroindustriais orgânicos, DL-Metionina e seus análogos, vermiculita e argilas '
+ 'expandidas, palhas e cascas de produ',
+ 'item': 7,
+ 'prefixes': ['0506',
+ '12011000',
+ '12130000',
+ '13019090',
+ '1302199',
+ '14019000',
+ '14049090',
+ '21022000',
+ '2302',
+ '2303',
+ '230400',
+ '23050000',
+ '2306',
+ '23080000',
+ '27030000',
+ '28399010',
+ '28399050',
+ '29224',
+ '293040',
+ '3301',
+ '38029040',
+ '380400',
+ '38249971',
+ '44013900',
+ '44014',
+ '44029000',
+ '47010000',
+ '53050090',
+ '68062000']},
+ {'clean': True,
+ 'description': 'Ácido nítrico, ácido sulfúrico, ácido fosfórico, fosfatos de cálcio naturais, enxofre, ácido clorídrico, ácido fosforoso, ácido acético, hidróxido de sódio e carbonato dissódico; '
+ 'todos destinados diretamente à fabricação de fertilizantes 2503.00.10 2503.00.90 2510.10.10 2510.10.90 2510.20.10 2510.20.90 2802.00.00 2806.10.20 2807.00.10 2808.00.10 2809.20.11 '
+ '2809.20.19 2811.19.20 2815.11.00 2815.12.',
+ 'item': 8,
+ 'prefixes': ['25030010',
+ '25030090',
+ '25101010',
+ '25101090',
+ '25102010',
+ '25102090',
+ '28020000',
+ '28061020',
+ '28070010',
+ '28080010',
+ '28092011',
+ '28092019',
+ '28111920',
+ '28151100',
+ '28151200',
+ '28362010',
+ '28362090',
+ '29152100']},
+ {'clean': True, 'description': 'Enzimas preparadas para decomposição de matéria orgânica animal e vegetal 3507.90.4', 'item': 9, 'prefixes': ['3507904']},
+ {'clean': False,
+ 'description': 'Semente genética, semente básica, semente nativa in natura, semente certificada de primeira geração (C1), semente certificada de segunda geração (C2), semente não certificada de '
+ 'primeira geração (S1), semente não certificada de segunda geração (S2) e sementes de cultivar local, tradicional ou crioula; em conformidade com as definições e demais requisitos da '
+ 'legislação específica Capítulos 7, 10 e ',
+ 'item': 10,
+ 'prefixes': []},
+ {'clean': False,
+ 'description': 'Mudas de plantas e demais materiais propagativos de plantas e fungos, inclusive plantas e fungos nativos de espécies florestais; em conformidade com as definições e demais requisitos '
+ 'da legislação específica 06.01 06.02',
+ 'item': 11,
+ 'prefixes': ['0601', '0602']},
+ {'clean': False,
+ 'description': 'Vacinas, soros e medicamentos, de uso veterinário, exceto de animais domésticos 3002.12 3002.15 3002.42 3002.90.00 30.04',
+ 'item': 12,
+ 'prefixes': ['300212', '300215', '300242', '30029000', '3004']},
+ {'clean': False, 'description': 'Aves de um dia, exceto as ornamentais 0105.1', 'item': 13, 'prefixes': ['01051']},
+ {'clean': True, 'description': 'Embriões e sêmen, congelado ou resfriado 0511.10.00 0511.9', 'item': 14, 'prefixes': ['05111000', '05119']},
+ {'clean': False,
+ 'description': 'Reprodutores de raça pura, inclusive matrizes de animais puros de origem com registro genealógico; em conformidade com as definições e demais requisitos da legislação específica 01.02 '
+ '01.03 01.04',
+ 'item': 15,
+ 'prefixes': ['0102', '0103', '0104']},
+ {'clean': True, 'description': 'Ovos fertilizados 0407.1', 'item': 16, 'prefixes': ['04071']},
+ {'clean': True, 'description': 'Girinos e alevinos 0106.90.00', 'item': 17, 'prefixes': ['01069000']},
+ {'clean': False, 'description': 'Rações para animais, concentrados, suplementos, aditivos, premix ou núcleo, exceto para animais domésticos 2309.90', 'item': 18, 'prefixes': ['230990']},
+ {'clean': False,
+ 'description': 'Sementes e cereais, mesmo triturados, em grãos esmagados ou trabalhados de outro modo; todos destinados diretamente à fabricação de ração para animais ou diretamente à alimentação '
+ 'animal, exceto de animais domésticos Capítulos 10, 11 e 12',
+ 'item': 19,
+ 'prefixes': []},
+ {'clean': False,
+ 'description': 'Farelos e tortas de produtos vegetais e demais resíduos e desperdícios das indústrias alimentares; todos destinados diretamente à fabricação de ração para animais ou diretamente à '
+ 'alimentação animal, exceto de animais domésticos 23.01 23.02 23.03 2304.00 2305.00.00 23.06 2308.00.00',
+ 'item': 20,
+ 'prefixes': ['2301', '2302', '2303', '230400', '23050000', '2306', '23080000']},
+ {'clean': False,
+ 'description': 'Alho em pó, sal mineralizado, farinhas de peixe, de ostra, de carne, de osso, de pena, de sangue e de víscera, calcário calcítico, gorduras e óleos animais, resíduos de óleo e de '
+ 'gordura de origem animal ou vegetal descartados por empresas do ramo alimentício, e DL-Metionina e seus análogos; todos destinados diretamente à fabricação de ração para animais ou '
+ 'diretamente à alimentação animal, exceto',
+ 'item': 21,
+ 'prefixes': ['0210', '0309', '07129010', '250100', '25210000', '293040']},
+ {'clean': True, 'description': 'Serviços agronômicos 1.1410.90.00', 'item': 22, 'prefixes': ['14109000']},
+ {'clean': True, 'description': 'Serviços de técnico agrícola, agropecuário ou em agroecologia 1.1410.90.00', 'item': 23, 'prefixes': ['14109000']},
+ {'clean': True, 'description': 'Serviços veterinários para produção animal 1.1405.21.00 1.1405.22.00 1.1405.90.00', 'item': 24, 'prefixes': ['14052100', '14052200', '14059000']},
+ {'clean': True, 'description': 'Serviços de zootecnistas 1.1410.90.00', 'item': 25, 'prefixes': ['14109000']},
+ {'clean': True, 'description': 'Serviços de inseminação e fertilização de animais de criação 1.1405.22.00', 'item': 26, 'prefixes': ['14052200']},
+ {'clean': True, 'description': 'Serviços de engenharia florestal 1.1403.10.00', 'item': 27, 'prefixes': ['14031000']},
+ {'clean': True, 'description': 'Serviços de pulverização e controle de pragas 1.1901.10.00', 'item': 28, 'prefixes': ['19011000']},
+ {'clean': True, 'description': 'Serviços de semeadura, adubação, inclusive mistura de adubos, reparação de solo, plantio e colheita 1.1901.10.00', 'item': 29, 'prefixes': ['19011000']},
+ {'clean': True, 'description': 'Serviços de projetos para irrigação e fertirrigação 1.1403.29.00', 'item': 30, 'prefixes': ['14032900']},
+ {'clean': True,
+ 'description': 'Serviços de análise laboratorial de solos, sementes e outros materiais propagativos, fitossanitários, água de produção, bromatologia e sanidade animal 1.1404.41.00',
+ 'item': 31,
+ 'prefixes': ['14044100']},
+ {'clean': True, 'description': 'Licenciamento de direitos sobre cultivares 1.1105.10.00', 'item': 32, 'prefixes': ['11051000']},
+ {'clean': True, 'description': 'Cessão definitiva de direitos sobre cultivares 1.1109.10.00', 'item': 33, 'prefixes': ['11091000']},
+ {'clean': False, 'description': 'Melhoramento genético de animais e plantas e biotecnologia, inclusive seus royalties', 'item': 34, 'prefixes': []},
+ {'clean': True, 'description': 'Vinhaça 2303.30.00 2303.20.00', 'item': 35, 'prefixes': ['23032000', '23033000']}],
+ 'number': 9,
+ 'revoked': False,
+ 'title': 'ANEXO IX INSUMOS AGROPECUÁRIOS E AQUÍCOLAS SUBMETIDOS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO NBS / NCM/SH 1 Biofertilizantes, em conformidade com as '
+ 'definiç'},
+ 'V': {'items': [{'clean': True,
+ 'description': 'ACESSÓRIOS E ADAPTAÇÕES ESPECIAIS PARA SEREM INSTALADOS EM VEÍCULOS AUTOMOTORES PERTENCENTES OU QUE FOREM DESTINADOS A PESSOAS COM DEFICIÊNCIA FÍSICA 1.1 Comando de embreagem manual, '
+ 'suas partes e acessórios 8708.99.10 1.2 Comando de freio manual, suas partes e acessórios 8708.99.10 1.3 Comando de acelerador manual, suas partes e acessórios 8708.99.10 1.4 Inversão '
+ 'do pedal do acelerador, suas part',
+ 'item': 1,
+ 'prefixes': ['84253110', '84289090', '87082999', '87089910']},
+ {'clean': True,
+ 'description': 'PRODUTOS DESTINADOS A USO DE PESSOA COM DEFICIÊNCIA VISUAL 2.1 Bengala inteiriça, dobrável ou telescópica, com ponteira de náilon 6602.00.00 2.2 Relógio em braille, com sintetizador de '
+ 'voz e mostrador ampliado 9102.11.10 9102.11.90 9102.91.00 2.3 Termômetro digital com sistema de voz 9025.19.90 2.4 Calculadora digital com sistema de voz, com verbalização dos ajustes '
+ 'de minutos e horas, tanto no mo',
+ 'item': 2,
+ 'prefixes': ['66020000', '84433222', '84701000', '84702900', '84716090', '84718000', '84729099', '85437099', '90172000', '90251990', '91021110', '91021190', '91029100']},
+ {'clean': True,
+ 'description': 'PRODUTOS DESTINADOS AO USO DE PESSOAS COM DEFICIÊNCIA AUDITIVA 3.1 Aparelho telefônico com teclado alfanumérico e visor luminoso, com ou sem impressora embutida, que permite converter '
+ 'sinais transmitidos por sistema telefônico em caracteres e símbolos 8517.1 3.2 Relógio despertador vibratório e/ou luminoso 9103.10.00 9105.11.00 3.3 Unidades de entrada de dados tipo '
+ 'mouse controláveis pelo moviment',
+ 'item': 3,
+ 'prefixes': ['84716053', '85171', '91031000', '91051100']}],
+ 'number': 5,
+ 'revoked': False,
+ 'title': 'ANEXO V DISPOSITIVOS DE ACESSIBILIDADE PRÓPRIOS PARA PESSOAS COM DEFICIÊNCIA SUBMETIDOS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO NCM/SH 1 ACESSÓRIOS E ADAPTAÇ'},
+ 'VI': {'items': [{'clean': True, 'description': 'Acetato de dextroalfatocoferol 2936.28.12', 'item': 1, 'prefixes': ['29362812']},
+ {'clean': True, 'description': 'Acetato de lisina 2922.41.90', 'item': 2, 'prefixes': ['29224190']},
+ {'clean': True, 'description': 'Acetato de potássio 2915.29.90', 'item': 3, 'prefixes': ['29152990']},
+ {'clean': True, 'description': 'Acetato de sódio 2915.29.10', 'item': 4, 'prefixes': ['29152910']},
+ {'clean': True, 'description': 'Acetato de zinco 2915.29.90', 'item': 5, 'prefixes': ['29152990']},
+ {'clean': True, 'description': 'Acetiltirosina 2922.50.39', 'item': 6, 'prefixes': ['29225039']},
+ {'clean': True, 'description': 'Ácido acético 2915.21.00', 'item': 7, 'prefixes': ['29152100']},
+ {'clean': True, 'description': 'Ácido ascórbico 2936.27.10', 'item': 8, 'prefixes': ['29362710']},
+ {'clean': True, 'description': 'Ácido aspártico 2922.49.90', 'item': 9, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Ácido cítrico 2918.14.00', 'item': 10, 'prefixes': ['29181400']},
+ {'clean': True, 'description': 'Ácido fólico 2936.29.11', 'item': 11, 'prefixes': ['29362911']},
+ {'clean': True, 'description': 'Ácido glutâmico 2922.42.10', 'item': 12, 'prefixes': ['29224210']},
+ {'clean': True, 'description': 'Ácido málico 2918.19.90', 'item': 13, 'prefixes': ['29181990']},
+ {'clean': True, 'description': 'Ácido selenioso 2811.19.90', 'item': 14, 'prefixes': ['28111990']},
+ {'clean': True, 'description': 'Água para injeção 2002.10.00', 'item': 15, 'prefixes': ['20021000']},
+ {'clean': True, 'description': 'Alanilglutamina 2922.49.90', 'item': 16, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Alanina 2922.49.90', 'item': 17, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Albumina humana 3002.12.36', 'item': 18, 'prefixes': ['30021236']},
+ {'clean': True, 'description': 'Arginina 2925.29.19', 'item': 19, 'prefixes': ['29252919']},
+ {'clean': True, 'description': 'Asparagina 2922.49.90', 'item': 20, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Bicarbonato de sódio 2836.30.00', 'item': 21, 'prefixes': ['28363000']},
+ {'clean': True, 'description': 'Biotina 2936.29.31', 'item': 22, 'prefixes': ['29362931']},
+ {'clean': True, 'description': 'Cianocobalamina 2936.26.10', 'item': 23, 'prefixes': ['29362610']},
+ {'clean': True, 'description': 'Cistina 2930.90.39', 'item': 24, 'prefixes': ['29309039']},
+ {'clean': True, 'description': 'Cloreto crômico 2827.39.93', 'item': 25, 'prefixes': ['28273993']},
+ {'clean': True, 'description': 'Cloreto de cálcio 2827.20.10 2827.20.90', 'item': 26, 'prefixes': ['28272010', '28272090']},
+ {'clean': True, 'description': 'Cloreto de magnésio 2827.31.10 2827.31.90', 'item': 27, 'prefixes': ['28273110', '28273190']},
+ {'clean': True, 'description': 'Cloreto de manganês 2827.39.95', 'item': 28, 'prefixes': ['28273995']},
+ {'clean': True, 'description': 'Cloreto de potássio 3104.20.10 3104.20.90', 'item': 29, 'prefixes': ['31042010', '31042090']},
+ {'clean': True, 'description': 'Cloreto de sódio 2501.00.90', 'item': 30, 'prefixes': ['25010090']},
+ {'clean': True, 'description': 'Cloreto de zinco 2827.39.98', 'item': 31, 'prefixes': ['28273998']},
+ {'clean': True, 'description': 'Cloridrato de piridoxina 2936.25.20', 'item': 32, 'prefixes': ['29362520']},
+ {'clean': True, 'description': 'Cloridrato de tiamina 2936.22.10', 'item': 33, 'prefixes': ['29362210']},
+ {'clean': True, 'description': 'Cocarboxilase 2936.22.90', 'item': 34, 'prefixes': ['29362290']},
+ {'clean': True, 'description': 'Colecalciferol 2936.29.21', 'item': 35, 'prefixes': ['29362921']},
+ {'clean': True, 'description': 'Ergocalciferol 2936.29.29', 'item': 36, 'prefixes': ['29362929']},
+ {'clean': True, 'description': 'Fenilalanina 2922.49.90', 'item': 37, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Fitomenadiona 2936.29.40', 'item': 38, 'prefixes': ['29362940']},
+ {'clean': True, 'description': 'Fórmula para dieta isenta de fenilalanina 2106.90.90', 'item': 39, 'prefixes': ['21069090']},
+ {'clean': True, 'description': 'Fórmula para dieta isenta demetionina 2106.90.90', 'item': 40, 'prefixes': ['21069090']},
+ {'clean': True, 'description': 'Fórmula para dieta isenta de lisina e pobre de triptofano 2106.90.90', 'item': 41, 'prefixes': ['21069090']},
+ {'clean': True, 'description': 'Fórmula para dieta isenta de leucina, de isoleucina ou de valina 2106.90.90', 'item': 42, 'prefixes': ['21069090']},
+ {'clean': True, 'description': 'Fórmula para dieta isenta de fenilalanina e de metionina 2106.90.90', 'item': 43, 'prefixes': ['21069090']},
+ {'clean': False, 'description': 'Fórmula para dieta isenta de aminoácidos não essenciais 2106.90.90', 'item': 44, 'prefixes': ['21069090']},
+ {'clean': True, 'description': 'Fórmula para dieta isenta de metionina, de treonina, de valina e restrita de isoleucina 2106.90.90', 'item': 45, 'prefixes': ['21069090']},
+ {'clean': True, 'description': 'Fórmula para dieta cetogênica, na proporção de 4 g de gordura para cada 1 g de carboidratos e proteínas 2106.90.90', 'item': 46, 'prefixes': ['21069090']},
+ {'clean': True, 'description': 'Fórmula hiperlipídica, para suplementação de triglicerídios de cadeia média ou triheptanoína 2202.99.00', 'item': 47, 'prefixes': ['22029900']},
+ {'clean': True, 'description': 'Preparação líquida, de quatro partes de trioleato de glicerol de ácido para uma parte de trierucato de glicerol 2202.99.00', 'item': 48, 'prefixes': ['22029900']},
+ {'clean': True, 'description': 'Fosfato de potássio dibásico 2835.24.00', 'item': 49, 'prefixes': ['28352400']},
+ {'clean': True, 'description': 'Fosfato de potássio monobásico 2835.24.00', 'item': 50, 'prefixes': ['28352400']},
+ {'clean': True, 'description': 'Fosfato de sódio monobásico 2835.22.00', 'item': 51, 'prefixes': ['28352200']},
+ {'clean': True, 'description': 'Fosfato de tiamina 2936.22.90', 'item': 52, 'prefixes': ['29362290']},
+ {'clean': True, 'description': 'Fosfato sódico de riboflavina 2936.23.20', 'item': 53, 'prefixes': ['29362320']},
+ {'clean': True, 'description': 'Frutose 1702.50.00', 'item': 54, 'prefixes': ['17025000']},
+ {'clean': True, 'description': 'Glicerofosfato de sódio 2919.90.90', 'item': 55, 'prefixes': ['29199090']},
+ {'clean': True, 'description': 'Glicina 2922.49.10', 'item': 56, 'prefixes': ['29224910']},
+ {'clean': True, 'description': 'Gliconato de cálcio 2918.16.10', 'item': 57, 'prefixes': ['29181610']},
+ {'clean': True, 'description': 'Glicose 1702.30.11', 'item': 58, 'prefixes': ['17023011']},
+ {'clean': True, 'description': 'Histidina 2933.29.92', 'item': 59, 'prefixes': ['29332992']},
+ {'clean': True, 'description': 'Icodextrina 3505.10.00', 'item': 60, 'prefixes': ['35051000']},
+ {'clean': True, 'description': 'Iodeto de potássio 2827.60.12', 'item': 61, 'prefixes': ['28276012']},
+ {'clean': True, 'description': 'Isoleucina 2922.49.90', 'item': 62, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Lecitina de ovo 2923.20.00', 'item': 63, 'prefixes': ['29232000']},
+ {'clean': True, 'description': 'Leucina 2922.49.90', 'item': 64, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Levovalina 2922.49.90', 'item': 65, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Lisina 2922.41.10', 'item': 66, 'prefixes': ['29224110']},
+ {'clean': True, 'description': 'Metionina 2930.40.10 2930.40.90', 'item': 67, 'prefixes': ['29304010', '29304090']},
+ {'clean': True, 'description': 'Nicotinamida 2936.29.52', 'item': 68, 'prefixes': ['29362952']},
+ {'clean': True, 'description': 'Palmitato de retinol 2936.21.13', 'item': 69, 'prefixes': ['29362113']},
+ {'clean': True, 'description': 'Prolina 2922.49.90', 'item': 70, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Riboflavina 2936.23.10', 'item': 71, 'prefixes': ['29362310']},
+ {'clean': True, 'description': 'Selenito de sódio 2842.90.00', 'item': 72, 'prefixes': ['28429000']},
+ {'clean': True, 'description': 'Serina 2922.50.99', 'item': 73, 'prefixes': ['29225099']},
+ {'clean': True, 'description': 'Sorbitol 2905.44.00', 'item': 74, 'prefixes': ['29054400']},
+ {'clean': True, 'description': 'Sulfato de magnésio 2833.21.00', 'item': 75, 'prefixes': ['28332100']},
+ {'clean': True, 'description': 'Sulfato de zinco 2833.29.70', 'item': 76, 'prefixes': ['28332970']},
+ {'clean': True, 'description': 'Taurina 2922.49.90', 'item': 77, 'prefixes': ['29224990']},
+ {'clean': True, 'description': 'Tirosina 2922.50.39', 'item': 78, 'prefixes': ['29225039']},
+ {'clean': True, 'description': 'Tocoferol 2936.28.11', 'item': 79, 'prefixes': ['29362811']},
+ {'clean': True, 'description': 'Treonina 2922.50.99', 'item': 80, 'prefixes': ['29225099']},
+ {'clean': True, 'description': 'Triglicerídeos de cadeia média 1513.19.00 1513.29.11', 'item': 81, 'prefixes': ['15131900', '15132911']}],
+ 'number': 6,
+ 'revoked': False,
+ 'title': 'ANEXO VI COMPOSIÇÕES PARA NUTRIÇÃO ENTERAL OU PARENTERAL E COMPOSIÇÕES ESPECIAIS E FÓRMULAS NUTRICIONAIS DESTINADAS ÀS PESSOAS COM ERROS INATOS DO METABOLISMO SUBMETIDAS À REDUÇÃO DE 60% (SESSENTA '
+ 'POR'},
+ 'VII': {'items': [{'clean': False,
+ 'description': 'Crustáceos (exceto lagostas e lagostim) e moluscos dos seguintes códigos e subposições da NCM/SH: a) 0306.1 e 0306.3, exceto os produtos da subposição 0306.11 e dos códigos '
+ '0306.15.00, 0306.31.00, 0306.34.00, 0306.39.10; e b) 0307.31.00, 0307.32.00, 0307.42.00, 0307.43, 0307.51.00, 0307.52.00, 0307.91.00 e 0307.92.00',
+ 'item': 1,
+ 'prefixes': ['03061', '030611', '03061500', '03063', '03063100', '03063400', '03063910', '03073100', '03073200', '03074200', '030743', '03075100', '03075200', '03079100', '03079200']},
+ {'clean': False,
+ 'description': 'Leite fermentado, bebidas e compostos lácteos, em conformidade com os requisitos da legislação específica, classificados nos códigos 0403.20.00, 0403.90.00 e 2202.99.00 da NCM/SH',
+ 'item': 2,
+ 'prefixes': ['04032000', '04039000', '22029900']},
+ {'clean': True, 'description': 'Mel natural do código 0409.00.00 da NCM/SH', 'item': 3, 'prefixes': ['04090000']},
+ {'clean': False,
+ 'description': 'Farinha das posições 1101.00, 11.02, 11.05, 11.06 e 12.08 da NCM/SH; ressalvados os produtos relacionados no Anexo I',
+ 'item': 4,
+ 'prefixes': ['110100', '1102', '1105', '1106', '1208']},
+ {'clean': False,
+ 'description': 'Grumos e sêmolas de cereais dos códigos 1103.11.00 e 1103.19.00 da NCM/SH; ressalvados os produtos relacionados no Anexo I',
+ 'item': 5,
+ 'prefixes': ['11031100', '11031900']},
+ {'clean': False, 'description': 'Grãos de cereais das subposições 1104.1 e 1104.2 da NCM/SH; ressalvados os produtos relacionados no Anexo I', 'item': 6, 'prefixes': ['11041', '11042']},
+ {'clean': True, 'description': 'Amido de milho do código 1108.12.00 da NCM/SH', 'item': 7, 'prefixes': ['11081200']},
+ {'clean': False,
+ 'description': 'Óleos de soja, de milho, canola e demais óleos vegetais, em conformidade com os requisitos da legislação específica relativos ao consumo como alimento, classificados na subposição '
+ '1507.90 e nas posições 15.08, 15.11, 15.12, 15.13, 15.14 e 15.15 da NCM/SH',
+ 'item': 8,
+ 'prefixes': ['150790', '1508', '1511', '1512', '1513', '1514', '1515']},
+ {'clean': True, 'description': 'Massas alimentícias dos códigos 1902.20.00 e 1902.30.00 da NCM/SH', 'item': 9, 'prefixes': ['19022000', '19023000']},
+ {'clean': True,
+ 'description': 'Sucos naturais de fruta ou de produtos hortícolas sem adição de açúcar ou de outros edulcorantes e sem conservantes classificados na posição 20.09 da NCM/SH',
+ 'item': 10,
+ 'prefixes': ['2009']},
+ {'clean': True,
+ 'description': 'Polpas de frutas ou de produtos hortícolas sem adição de açúcar ou de outros edulcorantes e sem conservantes classificadas na posição 20.08 da NCM/SH',
+ 'item': 11,
+ 'prefixes': ['2008']},
+ {'clean': True, 'description': 'Pão de Forma do código 1905.90.10 da NCM/SH', 'item': 12, 'prefixes': ['19059010']},
+ {'clean': True, 'description': 'Extrato de tomate classificado no código 2002.90.00 da NCM/SH', 'item': 13, 'prefixes': ['20029000']},
+ {'clean': False,
+ 'description': 'Frutas, produtos hortícolas e demais produtos vegetais, sem adição de açúcar ou de outros edulcorantes, classificados nos capítulos 7 e 8 da NCM/SH, ressalvados as frutas de casca '
+ 'rija não regionais e os produtos relacionados nos Anexos I e XV e excetuadas as posições 07.11, 08.12 e 0814.00.00',
+ 'item': 14,
+ 'prefixes': ['0711', '0812', '08140000']},
+ {'clean': False,
+ 'description': 'Cereais do capítulo 10 e sementes e frutos oleaginosos classificados no capítulo 12, ambos da NCM/SH, ressalvados os produtos relacionados no Anexo I',
+ 'item': 15,
+ 'prefixes': []},
+ {'clean': False,
+ 'description': 'Produtos hortícolas, mesmo misturados entre si, apenas pré-cozidos ou cozidos em água ou vapor, sem adição de sal ou de quaisquer outros produtos e substâncias, classificados nas '
+ 'posições 20.04 e 20.05 e no código 2002.10.00 da NCM/SH',
+ 'item': 16,
+ 'prefixes': ['20021000', '2004', '2005']},
+ {'clean': False,
+ 'description': 'Fruta de casca rija regional, amendoins e outras sementes, mesmo misturados entre si, apenas torrados ou cozidos, sem adição de sal ou de quaisquer outros produtos e substâncias, '
+ 'classificados na subposição 2008.1 da NCM/SH',
+ 'item': 17,
+ 'prefixes': ['20081']}],
+ 'number': 7,
+ 'revoked': False,
+ 'title': 'ANEXO VII ALIMENTOS DESTINADOS AO CONSUMO HUMANO SUBMETIDOS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO DO PRODUTO 1 Crustáceos (exceto lagostas e lagostim) e '
+ 'mo'},
+ 'VIII': {'items': [{'clean': True, 'description': 'Sabões de toucador classificados no código 3401.11.90 da NCM/SH', 'item': 1, 'prefixes': ['34011190']},
+ {'clean': True, 'description': 'Dentifrícios do código 3306.10.00 da NCM/SH', 'item': 2, 'prefixes': ['33061000']},
+ {'clean': True, 'description': 'Escovas de dentes do código 9603.21.00 da NCM/SH', 'item': 3, 'prefixes': ['96032100']},
+ {'clean': True, 'description': 'Papel higiênico do código 4818.10.00 da NCM/SH', 'item': 4, 'prefixes': ['48181000']},
+ {'clean': True, 'description': 'Água sanitária classificada no código 3808.94.19 da NCM/SH', 'item': 5, 'prefixes': ['38089419']},
+ {'clean': True, 'description': 'Sabões em barra classificados no código 3401.19.00 da NCM/SH', 'item': 6, 'prefixes': ['34011900']},
+ {'clean': True, 'description': 'Fraldas e artigos higiênicos semelhantes, de qualquer matéria classificadas no código 9619.00.00 da NCM/SH', 'item': 7, 'prefixes': ['96190000']}],
+ 'number': 8,
+ 'revoked': False,
+ 'title': 'ANEXO VIII PRODUTOS DE HIGIENE PESSOAL E LIMPEZA MAJORITARIAMENTE CONSUMIDOS POR FAMÍLIAS DE BAIXA RENDA SUBMETIDOS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO '
+ 'D'},
+ 'X': {'items': [{'clean': False, 'description': 'Licenciamento de direitos de autor e de direitos conexos 1.1103', 'item': 1, 'prefixes': []},
+ {'clean': True, 'description': 'Licenciamento de direitos de obras literárias 1.1103.10.00', 'item': 2, 'prefixes': ['11031000']},
+ {'clean': True, 'description': 'Licenciamento de direitos de autor de obras cinematográficas 1.1103.31.00', 'item': 3, 'prefixes': ['11033100']},
+ {'clean': True, 'description': 'Licenciamento de direitos de autor de obras jornalísticas 1.1103.32.00', 'item': 4, 'prefixes': ['11033200']},
+ {'clean': True, 'description': 'Licenciamento de direitos conexos de artistas intérpretes ou executantes em obras audiovisuais 1.1103.34.00', 'item': 5, 'prefixes': ['11033400']},
+ {'clean': True, 'description': 'Licenciamento de direitos conexos de produtores de obras audiovisuais 1.1103.35.00', 'item': 6, 'prefixes': ['11033500']},
+ {'clean': True, 'description': 'Licenciamento de direitos de obras audiovisuais destinadas à televisão 1.1103.36', 'item': 7, 'prefixes': ['110336']},
+ {'clean': True, 'description': 'Licenciamento de direitos de obras musicais e fonogramas 1.1103.4', 'item': 8, 'prefixes': ['11034']},
+ {'clean': True, 'description': 'Cessão temporária de direitos de obras literárias 1.1106.10.00', 'item': 9, 'prefixes': ['11061000']},
+ {'clean': True, 'description': 'Cessão temporária de direitos de autor de obras cinematográficas 1.1106.31.00', 'item': 10, 'prefixes': ['11063100']},
+ {'clean': True, 'description': 'Cessão temporária de direitos de autor de obras jornalísticas 1.1106.32.00', 'item': 11, 'prefixes': ['11063200']},
+ {'clean': True, 'description': 'Cessão temporária de direitos conexos de artistas intérpretes ou executantes em obras audiovisuais 1.1106.34.00', 'item': 12, 'prefixes': ['11063400']},
+ {'clean': True, 'description': 'Cessão temporária de direitos conexos de produtores de obras audiovisuais 1.1106.35.00', 'item': 13, 'prefixes': ['11063500']},
+ {'clean': True, 'description': 'Cessão temporária de direitos de obras audiovisuais destinadas à televisão 1.1106.36', 'item': 14, 'prefixes': ['110636']},
+ {'clean': True, 'description': 'Cessão temporária de direitos de obras musicais e fonogramas 1.1106.4', 'item': 15, 'prefixes': ['11064']},
+ {'clean': True, 'description': 'Cessão definitiva de direitos de obras literárias 1.1107.10.00', 'item': 16, 'prefixes': ['11071000']},
+ {'clean': True, 'description': 'Cessão definitiva de direitos de obras cinematográficas 1.1107.31.00', 'item': 17, 'prefixes': ['11073100']},
+ {'clean': True, 'description': 'Cessão definitiva de direitos de obras jornalísticas 1.1107.32.00', 'item': 18, 'prefixes': ['11073200']},
+ {'clean': True, 'description': 'Cessão definitiva de direitos de obras musicais e fonogramas 1.1107.40.00', 'item': 19, 'prefixes': ['11074000']},
+ {'clean': True, 'description': 'Serviços de agências de notícias para jornais e periódicos 1.1704.10.00', 'item': 20, 'prefixes': ['17041000']},
+ {'clean': True, 'description': 'Serviços de agências de notícias para mídia audiovisual 1. 1704.20.00', 'item': 21, 'prefixes': ['17042000']},
+ {'clean': True, 'description': 'Serviços de assistência e organização de convenções, feiras de negócios, exposições e outros eventos 1.1806.6', 'item': 22, 'prefixes': ['18066']},
+ {'clean': True,
+ 'description': 'Serviços de gravação de som em estúdio destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.11.00',
+ 'item': 23,
+ 'prefixes': ['25011100']},
+ {'clean': True,
+ 'description': 'Serviços de gravação de som ao vivo destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.12.00',
+ 'item': 24,
+ 'prefixes': ['25011200']},
+ {'clean': True, 'description': 'Serviços de produção de programas de televisão, videoteipes e filmes 1.2501.21.00', 'item': 25, 'prefixes': ['25012100']},
+ {'clean': True, 'description': 'Serviços de produção de programas de rádio 1.2501.22.00', 'item': 26, 'prefixes': ['25012200']},
+ {'clean': True,
+ 'description': 'Serviços de edição de obras audiovisuais destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.31.00',
+ 'item': 27,
+ 'prefixes': ['25013100']},
+ {'clean': True,
+ 'description': 'Serviços de duplicação e transferência de obras audiovisuais destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.32.00',
+ 'item': 28,
+ 'prefixes': ['25013200']},
+ {'clean': True,
+ 'description': 'Serviços de correção de cor e restauração digital de obras audiovisuais destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.33.00',
+ 'item': 29,
+ 'prefixes': ['25013300']},
+ {'clean': True,
+ 'description': 'Serviços de efeitos visuais em obras audiovisuais destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.34.00',
+ 'item': 30,
+ 'prefixes': ['25013400']},
+ {'clean': True, 'description': 'Serviços de animação destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.35.00', 'item': 31, 'prefixes': ['25013500']},
+ {'clean': True,
+ 'description': 'Serviços de legendas, títulos e dublagem em obras audiovisuais destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.36.00',
+ 'item': 32,
+ 'prefixes': ['25013600']},
+ {'clean': True,
+ 'description': 'Serviços de projeto e edição de som em obras audiovisuais destinados diretamente às produções nacionais artísticas, culturais e audiovisuais 1.2501.37.00',
+ 'item': 33,
+ 'prefixes': ['25013700']},
+ {'clean': True, 'description': 'Serviços de projeção de filmes 1.2501.50.00', 'item': 34, 'prefixes': ['25015000']},
+ {'clean': False, 'description': 'Serviços de produção audiovisual, de apoio e relacionados não classificados em subposições anteriores 1.2501.90.00', 'item': 35, 'prefixes': ['25019000']},
+ {'clean': True, 'description': 'Serviços de organização e promoção de atuações artísticas ao vivo 1.2502.10.00', 'item': 36, 'prefixes': ['25021000']},
+ {'clean': True, 'description': 'Serviços de produção e apresentação de atuações artísticas ao vivo, inclusive os ingressos relativos a estes serviços 1.2502.20.00', 'item': 37, 'prefixes': ['25022000']},
+ {'clean': True, 'description': 'Serviços de atuação artística 1.2503.10.00', 'item': 38, 'prefixes': ['25031000']},
+ {'clean': False, 'description': 'Serviços de autores, compositores, escultores, pintores e outros artistas, exceto os de atuação artística 1.2503.20.00', 'item': 39, 'prefixes': ['25032000']},
+ {'clean': True, 'description': 'Serviços de museus, inclusive serviços relativos a mostras e coleções de arte 1.2504.11.00', 'item': 40, 'prefixes': ['25041100']},
+ {'clean': True, 'description': 'Serviços de reservas de ingressos para eventos de produções nacionais artísticas, culturais e audiovisuais 1.1805.32.00', 'item': 41, 'prefixes': ['18053200']},
+ {'clean': True, 'description': 'Fotografias artísticas originais 4911.91.00', 'item': 42, 'prefixes': ['49119100']},
+ {'clean': True, 'description': 'Quadros, pinturas e desenhos, artísticos originais 9701.91.00', 'item': 43, 'prefixes': ['97019100']},
+ {'clean': True, 'description': 'Gravuras, estampas e litografias, artísticas originais 9702.90.00', 'item': 44, 'prefixes': ['97029000']},
+ {'clean': True, 'description': 'Produções originais de arte estatutária ou de escultura 9703.90.00', 'item': 45, 'prefixes': ['97039000']},
+ {'clean': True, 'description': 'Licenciamento de direitos conexos de artistas intérpretes ou executantes 1.1103.42.00', 'item': 46, 'prefixes': ['11034200']},
+ {'clean': False, 'description': 'Cessão temporária de direitos de autor e de direitos conexos 1.1106', 'item': 47, 'prefixes': []},
+ {'clean': True, 'description': 'Cessão temporária de direitos conexos de artistas intérpretes ou executantes 1.1106.42.00', 'item': 48, 'prefixes': ['11064200']},
+ {'clean': False, 'description': 'Licenciamento de direitos de autor de obras teatrais', 'item': 49, 'prefixes': []},
+ {'clean': False, 'description': 'Licenciamento de direitos conexos de produtores de obras teatrais', 'item': 50, 'prefixes': []},
+ {'clean': False, 'description': 'Licenciamento de direitos conexos de artistas intérpretes ou executantes em obras teatrais', 'item': 51, 'prefixes': []},
+ {'clean': False, 'description': 'Cessão temporária de direitos de autor de obras teatrais', 'item': 52, 'prefixes': []},
+ {'clean': False, 'description': 'Cessão temporária de direitos conexos de artistas intérpretes ou executantes em obras teatrais', 'item': 53, 'prefixes': []},
+ {'clean': False, 'description': 'Cessão temporária de direitos conexos de produtores intérpretes ou executantes em obras teatrais', 'item': 54, 'prefixes': []},
+ {'clean': True,
+ 'description': 'Serviços de sonorização, iluminação, figurino, videografia e cenografia para atuações artísticas ao vivo, destinados às produções de que trata o art. 139 desta Lei Complementar '
+ '1.2502.30.00',
+ 'item': 55,
+ 'prefixes': ['25023000']},
+ {'clean': True,
+ 'description': 'Serviços de locação, montagem e desmontagem de palcos, destinados às produções de que trata o art. 139 desta Lei Complementar 1.0105.70.00',
+ 'item': 56,
+ 'prefixes': ['01057000']},
+ {'clean': True,
+ 'description': 'Serviços de apresentação e promoção de atuações artísticas, inclusive gestão de espaços destinados a apresentações de exposições de artes cênicas, espetáculos e demais produções de que '
+ 'trata o art. 139 desta Lei Complementar 1.2502.90.00',
+ 'item': 57,
+ 'prefixes': ['25029000']}],
+ 'number': 10,
+ 'revoked': False,
+ 'title': 'ANEXO X PRODUÇÕES NACIONAIS ARTÍSTICAS, CULTURAIS, DE EVENTOS, JORNALÍSTICAS E AUDIOVISUAIS SUBMETIDAS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO NBS/NCM 1 Lice'},
+ 'XI': {'items': [{'clean': False,
+ 'description': 'SERVIÇOS RELACIONADOS À SOBERANIA E À SEGURANÇA NACIONAL, À SEGURANÇA DA INFORMAÇÃO E À SEGURANÇA CIBERNÉTICA 1.1 Segurança em Tecnologia da Informação (TI) 1.1501.20.00 1.2 Serviços '
+ 'de projeto e desenvolvimento de aplicativos e programas em Tecnologia da Informação (TI) não classificados em subposições anteriores 1.1502.90.00 1.3 Serviços de Tecnologia da '
+ 'Informação (TI) não classificados em subp',
+ 'item': 1,
+ 'prefixes': ['15012000', '15029000', '15100000', '18023000', '18029000', '20013500', '20018300']},
+ {'clean': False,
+ 'description': 'BENS RELACIONADOS À SOBERANIA E À SEGURANÇA NACIONAL, À SEGURANÇA DA INFORMAÇÃO E À SEGURANÇA CIBERNÉTICA 2.1 Viatura operacional militar e também suas partes e peças 8709 2.2 Carro '
+ 'blindado e carro de combate, terrestre ou anfíbio, sobre lagartas ou rodas, com ou sem armamento e também suas partes e peças 8710.00.00 2.3 Outros veículos de qualquer tipo, para uso '
+ 'pelos órgãos de Segurança Pública ',
+ 'item': 2,
+ 'prefixes': ['21069030',
+ '36020000',
+ '84714900',
+ '84715090',
+ '84719014',
+ '85176234',
+ '8517624',
+ '85176259',
+ '8517627',
+ '852351',
+ '852352',
+ '85258929',
+ '85261000',
+ '87100000',
+ '88026000',
+ '88040000',
+ '88051000',
+ '88052100',
+ '89012000',
+ '89061000',
+ '901420',
+ '90318099',
+ '93012000',
+ '93062']}],
+ 'number': 11,
+ 'revoked': False,
+ 'title': 'ANEXO XI BENS E SERVIÇOS RELACIONADOS À SOBERANIA E À SEGURANÇA NACIONAL, À SEGURANÇA DA INFORMAÇÃO E À SEGURANÇA CIBERNÉTICA SUBMETIDOS À REDUÇÃO DE 60% (SESSENTA POR CENTO) DAS ALÍQUOTAS DO IBS E '
+ 'DA'},
+ 'XII': {'items': [{'clean': False,
+ 'description': 'Aparelhos de eletrodiagnóstico (incluídos os aparelhos de exploração funcional e os de verificação de parâmetros fisiológicos) 1.1 Eletrocardiógrafos 9018.11.00 1.2 '
+ 'Eletroencefalógrafos 9018.19.80 1.3 Aparelhos de eletrodiagnóstico, exceto os produtos classificados nos códigos 9018.11.00, 9018.12.10, 9018.12.90, 9018.13.00, 9018.14.10, '
+ '9018.14.20, 9018.14.90, 9018.19.10 e 9018.19.20 9018.19.80',
+ 'item': 1,
+ 'prefixes': ['90181100', '90181210', '90181290', '90181300', '90181410', '90181420', '90181490', '90181910', '90181920', '90181980']},
+ {'clean': True, 'description': 'Aparelhos de raios ultravioleta ou infravermelhos 9018.20', 'item': 2, 'prefixes': ['901820']},
+ {'clean': True, 'description': 'Artigos e aparelhos ortopédicos 9021.10.10', 'item': 3, 'prefixes': ['90211010']},
+ {'clean': True, 'description': 'Artigos e aparelhos para fraturas 9021.10.20', 'item': 4, 'prefixes': ['90211020']},
+ {'clean': False,
+ 'description': 'Artigos e aparelhos de prótese, exceto os dentários e os produtos classificados nos códigos 9021.39.91 e 9021.39.99 9021.3',
+ 'item': 5,
+ 'prefixes': ['90213', '90213991', '90213999']},
+ {'clean': True, 'description': 'Tomógrafo computadorizado 9022.12.00', 'item': 6, 'prefixes': ['90221200']},
+ {'clean': False,
+ 'description': 'Aparelhos de raio X, móveis, exceto os produtos classificados no código 9022.19.91 9022.13 9022.14 9022.19',
+ 'item': 7,
+ 'prefixes': ['902213', '902214', '902219', '90221991']},
+ {'clean': True, 'description': 'Aparelho de radiocobalto (bomba de cobalto) 9022.21.10', 'item': 8, 'prefixes': ['90222110']},
+ {'clean': True, 'description': 'Aparelho de crioterapia 9018.90.99', 'item': 9, 'prefixes': ['90189099']},
+ {'clean': True, 'description': 'Aparelho de gamaterapia 9022.21.20', 'item': 10, 'prefixes': ['90222120']},
+ {'clean': False,
+ 'description': 'Aparelhos que utilizem radiações alfa, beta, gama ou outras radiações ionizantes, para usos médicos, cirúrgicos, odontológicos ou veterinários, incluídos os aparelhos de '
+ 'radiofotografia ou de radioterapia, exceto os produtos classificados nos códigos 9022.21.10 e 9022.21.20 9022.21.90',
+ 'item': 11,
+ 'prefixes': ['90222110', '90222120', '90222190']},
+ {'clean': False,
+ 'description': 'Densímetros, areômetros, pesa-líquidos e instrumentos flutuantes semelhantes, termômetros, pirômetros, barômetros, higrômetros e psicômetros, registradores ou não, mesmo combinados '
+ 'entre si 90.25',
+ 'item': 12,
+ 'prefixes': ['9025']},
+ {'clean': True, 'description': 'Respirador 9019.20.40', 'item': 13, 'prefixes': ['90192040']},
+ {'clean': True, 'description': 'Monitor multiparâmetros 9018.19.80', 'item': 14, 'prefixes': ['90181980']},
+ {'clean': True, 'description': 'Bomba de infusão 9018.90.10', 'item': 15, 'prefixes': ['90189010']},
+ {'clean': True, 'description': 'Aparelhos de diagnóstico por visualização de ressonância magnética 9018.13.00', 'item': 16, 'prefixes': ['90181300']},
+ {'clean': True, 'description': 'Aparelhos de ultrassom 9018.12', 'item': 17, 'prefixes': ['901812']}],
+ 'number': 12,
+ 'revoked': False,
+ 'title': 'ANEXO XII DISPOSITIVOS MÉDICOS SUBMETIDOS À REDUÇÃO A ZERO DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO NCM/SH 1 Aparelhos de eletrodiagnóstico (incluídos os aparelhos de exploração funcional e os '
+ 'de '},
+ 'XIII': {'items': [{'clean': True, 'description': 'Barra de apoio para pessoa com deficiência física 8302.41.00', 'item': 1, 'prefixes': ['83024100']},
+ {'clean': True,
+ 'description': 'CADEIRA DE RODAS E OUTROS VEÍCULOS PARA DEFICIENTES, MESMO COM MOTOR OU OUTRO MECANISMO DE PROPULSÃO 2.1 Sem mecanismo de propulsão 8713.10.00 2.2 Cadeiras de rodas com motor ou '
+ 'outro mecanismo de propulsão e outros veículos para pessoas com incapacidade, mesmo com motor ou outro mecanismo de propulsão 8713.90.00',
+ 'item': 2,
+ 'prefixes': ['87131000', '87139000']},
+ {'clean': False,
+ 'description': 'Partes e acessórios destinados exclusivamente a aplicação em cadeiras de rodas ou em outros veículos para deficientes 8714.20.00',
+ 'item': 3,
+ 'prefixes': ['87142000']},
+ {'clean': False, 'description': 'Aparelhos para facilitar a audição dos surdos, exceto partes e acessórios 9021.40.00', 'item': 4, 'prefixes': ['90214000']},
+ {'clean': True, 'description': 'Partes e acessórios de aparelhos para facilitar a audição dos surdos 9021.90.92', 'item': 5, 'prefixes': ['90219092']},
+ {'clean': True, 'description': 'Implantes cocleares 9021.90.19', 'item': 6, 'prefixes': ['90219019']}],
+ 'number': 13,
+ 'revoked': False,
+ 'title': 'ANEXO XIII DISPOSITIVOS DE ACESSIBILIDADE PRÓPRIOS PARA PESSOAS COM DEFICIÊNCIA SUBMETIDOS À REDUÇÃO A ZERO DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO NCM/SH 1 Barra de apoio para pessoa com '
+ 'deficiê'},
+ 'XIV': {'items': [{'clean': True, 'description': 'ABACAVIR 3004.90.69', 'item': 1, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'ABEMACICLIBE 3004.90.69', 'item': 2, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'ACALABRUTINIBE 3004.90.69', 'item': 3, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'ACEPONATO DE METILPREDNISOLONA 3004.32.10', 'item': 4, 'prefixes': ['30043210']},
+ {'clean': True, 'description': 'ACETATO DE ABIRATERONA 3004.32.90', 'item': 5, 'prefixes': ['30043290']},
+ {'clean': True, 'description': 'ACETATO DE CIPROTERONA 3004.39.39', 'item': 6, 'prefixes': ['30043939']},
+ {'clean': True, 'description': 'ACETATO DE DEGARELIX 3004.39.29', 'item': 7, 'prefixes': ['30043929']},
+ {'clean': True, 'description': 'ACETATO DE GOSSERRELINA 3004.39.27', 'item': 8, 'prefixes': ['30043927']},
+ {'clean': True, 'description': 'ACETATO DE LEUPRORRELINA 3004.39.19', 'item': 9, 'prefixes': ['30043919']},
+ {'clean': True, 'description': 'ACETATO DE MEGESTROL 3004.39.36', 'item': 10, 'prefixes': ['30043936']},
+ {'clean': True, 'description': 'ACETATO DE OCTREOTIDA 3004.39.29', 'item': 11, 'prefixes': ['30043929']},
+ {'clean': True, 'description': 'ACETATO DE TRIPTORRELINA 3004.39.18', 'item': 12, 'prefixes': ['30043918']},
+ {'clean': True, 'description': 'ACETATO DESMOPRESSINA 3004.39.29', 'item': 13, 'prefixes': ['30043929']},
+ {'clean': True, 'description': 'ÁCIDO FOLÍNICO (FÓLICO) 3004.50.90', 'item': 14, 'prefixes': ['30045090']},
+ {'clean': True, 'description': 'ÁCIDO TRANEXÂMICO 3004.90.39', 'item': 15, 'prefixes': ['30049039']},
+ {'clean': True, 'description': 'ÁCIDO ZOLEDRÔNICO 3004.90.69', 'item': 16, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'ACITRETINA 3004.90.29', 'item': 17, 'prefixes': ['30049029']},
+ {'clean': True, 'description': 'AFLIBERCEPTE 3002.15.90', 'item': 18, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'ALBINTERFERONA ALFA-2B 3002.15.90', 'item': 19, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'ALBUMINA HUMANA 3002.12.39', 'item': 20, 'prefixes': ['30021239']},
+ {'clean': True, 'description': 'ALENDRONATO DE SÓDIO 3004.90.59', 'item': 21, 'prefixes': ['30049059']},
+ {'clean': True, 'description': 'ALENTUZUMABE 3002.15.90', 'item': 22, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'ALFA-ALGLICOSIDASE 3004.90.19', 'item': 23, 'prefixes': ['30049019']},
+ {'clean': True, 'description': 'ALFAELOSULFASE 3004.90.19', 'item': 24, 'prefixes': ['30049019']},
+ {'clean': True, 'description': 'ALFAEPOETINA 3002.12.39', 'item': 25, 'prefixes': ['30021239']},
+ {'clean': True, 'description': 'ALFAINTERFERONA 3002.15.90', 'item': 26, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'ALFAPEGINTERFERONA 2A 3002.15.10', 'item': 27, 'prefixes': ['30021510']},
+ {'clean': True, 'description': 'ALFAPEGINTERFERONA 2B 3002.15.90', 'item': 28, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'ALFATIROTROPINA 3004.39.29', 'item': 29, 'prefixes': ['30043929']},
+ {'clean': True, 'description': 'ALFAVESTRONIDASE 3004.90.19', 'item': 30, 'prefixes': ['30049019']},
+ {'clean': True, 'description': 'ALPELISIBE 3004.90.79', 'item': 31, 'prefixes': ['30049079']},
+ {'clean': True, 'description': 'ALTEPLASE 3004.90.19', 'item': 32, 'prefixes': ['30049019']},
+ {'clean': True, 'description': 'AMBRISENTANA 3004.90.79', 'item': 33, 'prefixes': ['30049079']},
+ {'clean': True, 'description': 'AMIFOSTINA 3004.90.59', 'item': 34, 'prefixes': ['30049059']},
+ {'clean': True, 'description': 'ANASTROZOL 3004.90.69', 'item': 35, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'ANFOTERICINA B 3004.20.99', 'item': 36, 'prefixes': ['30042099']},
+ {'clean': True, 'description': 'ANFOTERICINA B EM LIPOSSOMAS 3004.20.95', 'item': 37, 'prefixes': ['30042095']},
+ {'clean': True, 'description': 'ANTIMONIAL PENTAVALENTE 3004.90.29', 'item': 38, 'prefixes': ['30049029']},
+ {'clean': True, 'description': 'APALUTAMIDA 3004.90.69', 'item': 39, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'APREPITANTO 3004.90.78', 'item': 40, 'prefixes': ['30049078']},
+ {'clean': True, 'description': 'ARTEMÉTER 3004.60.00', 'item': 41, 'prefixes': ['30046000']},
+ {'clean': True, 'description': 'ARTEMÉTER + LUMEFANTRINA 3004.60.00', 'item': 42, 'prefixes': ['30046000']},
+ {'clean': True, 'description': 'ARTESUNATO + CLORIDRATO MEFLOQUINA 3004.60.00', 'item': 43, 'prefixes': ['30046000']},
+ {'clean': True, 'description': 'ARTESUNATO DE SÓDIO 3004.60.00', 'item': 44, 'prefixes': ['30046000']},
+ {'clean': True, 'description': 'ASPARAGINASE 3004.90.12', 'item': 45, 'prefixes': ['30049012']},
+ {'clean': True, 'description': 'ATENOLOL 3004.90.42', 'item': 46, 'prefixes': ['30049042']},
+ {'clean': True, 'description': 'ATEZOLIZUMABE 3002.15.90', 'item': 47, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'AVELUMABE 3002.15.90', 'item': 48, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'AXITINIBE 3004.90.69', 'item': 49, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'AZACITIDINA 3004.90.79', 'item': 50, 'prefixes': ['30049079']},
+ {'clean': True, 'description': 'AZATIOPRINA 3004.90.66', 'item': 51, 'prefixes': ['30049066']},
+ {'clean': True, 'description': 'BARICITINIBE 3004.90.79', 'item': 52, 'prefixes': ['30049079']},
+ {'clean': True, 'description': 'BENZONIDAZOL 3004.90.69', 'item': 53, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'BESILATO DE ANLODIPINO 3004.90.69', 'item': 54, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'BETAEPOETINA 3002.12.39', 'item': 55, 'prefixes': ['30021239']},
+ {'clean': True, 'description': 'BEVACIZUMABE 3002.15.20', 'item': 56, 'prefixes': ['30021520']},
+ {'clean': True, 'description': 'BICALUTAMIDA 3004.90.59', 'item': 57, 'prefixes': ['30049059']},
+ {'clean': True, 'description': 'BIOTINA 2936.29.31', 'item': 58, 'prefixes': ['29362931']},
+ {'clean': True, 'description': 'BLINATUMOMABE 3002.15.90', 'item': 59, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'BORTEZOMIBE 3004.90.68', 'item': 60, 'prefixes': ['30049068']},
+ {'clean': True, 'description': 'BRENTUXIMABE VEDOTINA 3002.15.90', 'item': 61, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'BRIGATINIBE 3004.90.69', 'item': 62, 'prefixes': ['30049069']},
+ {'clean': True, 'description': 'BROMETO DE IPRATRÓPIO 3004.49.90', 'item': 63, 'prefixes': ['30044990']},
+ {'clean': True, 'description': 'BUDESONIDA 3004.39.99', 'item': 64, 'prefixes': ['30043999']},
+ {'clean': True, 'description': 'BUROSUMABE 3002.15.80', 'item': 65, 'prefixes': ['30021580']},
+ {'clean': True, 'description': 'BUSSULFANO 3004.90.95', 'item': 66, 'prefixes': ['30049095']},
+ {'clean': True, 'description': 'CABAZITAXEL 3004.90.59', 'item': 67, 'prefixes': ['30049059']},
+ {'clean': True, 'description': 'CAPECITABINA 3004.90.79', 'item': 68, 'prefixes': ['30049079']},
+ {'clean': True, 'description': 'CARBIDOPA + LEVODOPA 3004.90.35', 'item': 69, 'prefixes': ['30049035']},
+ {'clean': True, 'description': 'CARBOPLATINA 3004.90.99', 'item': 70, 'prefixes': ['30049099']},
+ {'clean': True, 'description': 'CARFILZOMIBE 3004.90.79', 'item': 71, 'prefixes': ['30049079']},
+ {'clean': True, 'description': 'CARMUSTINA 3004.90.48', 'item': 72, 'prefixes': ['30049048']},
+ {'clean': True, 'description': 'CEFALOTINA 3004.20.59', 'item': 73, 'prefixes': ['30042059']},
+ {'clean': True, 'description': 'CEFOXITINA 3004.20.59', 'item': 74, 'prefixes': ['30042059']},
+ {'clean': True, 'description': 'CEFTAZIDIMA 3004.20.59', 'item': 75, 'prefixes': ['30042059']},
+ {'clean': True, 'description': 'CELECOXIBE 3004.90.79', 'item': 76, 'prefixes': ['30049079']},
+ {'clean': True, 'description': 'CETUXIMABE 3002.15.90', 'item': 77, 'prefixes': ['30021590']},
+ {'clean': True, 'description': 'CICLOFOSFAMIDA 3004.90.79', 'item': 78, 'prefixes': ['30049079']},
+ {'clean': True, 'description': 'CILASTATINA SÓDICA + IMIPENEM 3004.20.94', 'item': 79, 'prefixes': ['30042094']},
+ {'clean': True, 'description': 'CISPLATINA 3004.90.99', 'item': 80, 'prefixes': ['30049099']},
+ {'clean': True, 'description': 'CITARABINA 3004.90.79', 'item': 81, 'prefixes': ['30049079']},
+ {'clean': True,
+ 'description': 'CITRATO DE IXAZOMIBE 3004.90.59 84 CITRATO DE TAMOXIFENO 3004.90.34 85 CLADRIBINA 3004.90.79 86 CLODRONATO DISSÓDICO 3004.90.58 87 CLOFAZIMINA 3004.90.69 88 CLORAMBUCILA 3004.90.38 '
+ '89 CLORETO DE RÁDIO (223 RA) 2844.42.00 90 CLORETO DE SÓDIO 2501.00.90 91 CLORETO DE SUXAMETÔNIO 3004.90.99 92 CLORIDRATO DE ALECTINIBE 3004.90.79 93 CLORIDRATO DE ALFENTANILA '
+ 'MONOIDRATADA 3004.90.69 94 CLORIDRATO DE AM',
+ 'item': 82,
+ 'prefixes': ['25010090',
+ '28444200',
+ '30021211',
+ '30021212',
+ '30021215',
+ '30021219',
+ '30021239',
+ '30021510',
+ '30021520',
+ '30021590',
+ '30022032',
+ '30024121',
+ '30024122',
+ '30024123',
+ '30024125',
+ '30024127',
+ '30024129',
+ '30029000',
+ '30042032',
+ '30042063',
+ '30042069',
+ '30042071',
+ '30042091',
+ '30042093',
+ '30042099',
+ '30043039',
+ '30043100',
+ '30043210',
+ '30043220',
+ '30043290',
+ '30043918',
+ '30043926',
+ '30043927',
+ '30043929',
+ '30043936',
+ '30043939',
+ '30043994',
+ '30044910',
+ '30044950',
+ '30044990',
+ '30045010',
+ '30045090',
+ '30049014',
+ '30049019',
+ '30049029',
+ '30049034',
+ '30049038',
+ '30049039',
+ '30049041',
+ '30049043',
+ '30049047',
+ '30049048',
+ '30049049',
+ '30049058',
+ '30049059',
+ '30049063',
+ '30049064',
+ '30049068',
+ '30049069',
+ '30049072',
+ '30049076',
+ '30049078',
+ '30049079',
+ '30049095',
+ '30049099',
+ '30063013']}],
+ 'number': 14,
+ 'revoked': True,
+ 'title': 'ANEXO XIV (Revogado pela Lei Complementar nº 227, de 2026) MEDICAMENTOS SUBMETIDOS À REDUÇÃO A ZERO DAS ALÍQUOTAS DO IBS E DA CB S ITEM DESCRIÇÃO NCM/SH 1 ABACAVIR 3004.90.69 2 ABEMACICLIBE '
+ '3004.90.69'},
+ 'XV': {'items': [{'clean': True, 'description': 'Ovos da subposição 0407.2 da NCM/SH', 'item': 1, 'prefixes': ['04072']},
+ {'clean': False,
+ 'description': 'Produtos hortícolas das posições 07.01, 07.02.00.00, 07.03, 07.04, 07.05, 07.06, 0707.00.00, 07.08, 07.09 e 07.10, exceto os cogumelos e trufas classificados na subposição 0709.5 e no '
+ 'código 0710.80.00 da NCM/SH',
+ 'item': 2,
+ 'prefixes': ['0701', '07020000', '0703', '0704', '0705', '0706', '07070000', '0708', '0709', '07095', '0710', '07108000']},
+ {'clean': True,
+ 'description': 'Frutas frescas ou refrigeradas e frutas congeladas sem adição de açúcar ou de outros edulcorantes classificadas nas posições 08.03, 08.04, 08.05, 08.06, 08.07, 08.08, 08.09, 08.10 e '
+ '08.11 da NCM/SH',
+ 'item': 3,
+ 'prefixes': ['0803', '0804', '0805', '0806', '0807', '0808', '0809', '0810', '0811']},
+ {'clean': False,
+ 'description': 'Plantas e produtos de floricultura relativos à horticultura e cultivados para fins alimentares, ornamentais ou medicinais classificados no Capítulo 6 da NCM/SH',
+ 'item': 4,
+ 'prefixes': []},
+ {'clean': True, 'description': 'Raízes e tubérculos da posição 07.14 da NCM/SH', 'item': 5, 'prefixes': ['0714']},
+ {'clean': True, 'description': 'Cocos da subposição 0801.1 da NCM/SH', 'item': 6, 'prefixes': ['08011']}],
+ 'number': 15,
+ 'revoked': False,
+ 'title': 'ANEXO XV PRODUTOS HORTÍCOLAS, FRUTAS E OVOS SUBMETIDOS À REDUÇÃO DE 100% (CEM POR CENTO) DAS ALÍQUOTAS DO IBS E DA CBS ITEM DESCRIÇÃO DO PRODUTO 1 Ovos da subposição 0407.2 da NCM/SH 2 Produtos '
+ 'hortíc'}}
diff --git a/central/app/version.py b/central/app/version.py
index dea364e..6a1b769 100644
--- a/central/app/version.py
+++ b/central/app/version.py
@@ -4,5 +4,5 @@ kept identical to this) and what an AgentRelease row's `version` column holds
once published — never a second, independent version number. Fiscal semantics
are versioned separately (ENGINE_VERSION/DECISION_VERSION in classification.py,
DECISION_ENGINE_VERSION etc.) and are NOT changed by a release bump."""
-GTI_FISCAL_VERSION = "1.1.8"
+GTI_FISCAL_VERSION = "1.1.9"
API_COMPAT_MAJOR_MINOR = "1.0" # an Agent 1.0.x/1.1.x talks to any Hub 1.0.x
diff --git a/central/app/web.py b/central/app/web.py
index 4886961..4dadf6a 100644
--- a/central/app/web.py
+++ b/central/app/web.py
@@ -296,7 +296,7 @@ def router(session_factory):
if installation.processing_enabled and last_sync is not None:
next_sync = last_sync + timedelta(seconds=installation.sync_interval_seconds)
last_summary = session.scalar(select(Job.result_summary).where(Job.agent_id == agent.id, Job.status == "COMPLETED", Job.kind.in_(("INITIAL_SYNC", "SYNC_INCREMENTAL", "REPROCESS_ALL"))).order_by(Job.id.desc()).limit(1))
- return {"rtc": rtc_status_view(last_summary), "enabled": bool(installation.processing_enabled), "interval_minutes": installation.sync_interval_seconds // 60,
+ return {"rtc": rtc_status_view(last_summary, bool(installation.rtc_auto_apply_authorized)), "rtc_authorized": bool(installation.rtc_auto_apply_authorized), "enabled": bool(installation.processing_enabled), "interval_minutes": installation.sync_interval_seconds // 60,
"last_sync": format_ui_datetime(last_sync) if last_sync else None, "next_sync": format_ui_datetime(next_sync) if next_sync else None,
"last_changed": installation.last_sync_changed, "last_job": {"kind": last_job.kind, "status": last_job.status, "id": last_job.id, "kind_label": job_kind_label(last_job.kind), "status_label": job_status_label(last_job.status)} if last_job else None}
@@ -319,6 +319,32 @@ def router(session_factory):
return RedirectResponse(f"/agents/{agent_id}?tab=jobs", status_code=303)
finally: session.close()
+ @routes.post("/agents/{agent_id}/rtc-auto-apply")
+ async def rtc_auto_apply_authorization(request: Request, agent_id: int):
+ """Central authorization of the automatic cClassTrib fill (default OFF). Enabling requires an explicit typed confirmation; every change is audited."""
+ session, auth_data, redirect = page_auth(request)
+ if redirect: return redirect
+ try:
+ values = await form_values(request); web_session, admin = auth_data
+ require_csrf(web_session, values.get("csrf_token"))
+ agent = session.get(Agent, agent_id)
+ installation = session.scalar(select(Installation).where(Installation.agent_id == agent_id)) if agent else None
+ if not agent or not installation: return HTMLResponse("Agent not found", status_code=404)
+ decision = values.get("decision")
+ if decision == "authorize":
+ if (values.get("confirm") or "").strip().upper() != "PREENCHER":
+ return HTMLResponse("Digite PREENCHER para confirmar a autorização", status_code=422)
+ installation.rtc_auto_apply_authorized = True
+ elif decision == "revoke":
+ installation.rtc_auto_apply_authorized = False
+ else:
+ return HTMLResponse("decisão inválida", status_code=422)
+ record_audit(session, admin_user_id=admin.id, tenant_id=installation.tenant_id, action=f"RTC_AUTO_APPLY_{decision.upper()}", target_type="installation", target_id=installation.installation_id,
+ context={"authorized": installation.rtc_auto_apply_authorized}, severity="WARNING")
+ session.commit()
+ return RedirectResponse(f"/agents/{agent_id}", status_code=303)
+ finally: session.close()
+
@routes.post("/agents/{agent_id}/sync-now")
async def sync_now(request: Request, agent_id: int):
return await _installation_action(request, agent_id, "sync-now")
diff --git a/central/pyproject.toml b/central/pyproject.toml
index 3e9b130..6dd01ef 100644
--- a/central/pyproject.toml
+++ b/central/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "gti-fiscal-hub"
-version = "1.1.8"
+version = "1.1.9"
requires-python = ">=3.10"
dependencies = [
"fastapi>=0.115,<1",
diff --git a/central/templates/agent_detail.html b/central/templates/agent_detail.html
index 2af1a4c..18ef3ee 100644
--- a/central/templates/agent_detail.html
+++ b/central/templates/agent_detail.html
@@ -8,7 +8,9 @@
Reprocessar tudo
{% if ops.enabled %}{% else %}{% endif %}
-- Processamento
- {{ "Ativo" if ops.enabled else "Pausado" }} · sincronização automática a cada {{ ops.interval_minutes }} min
- Última sincronização
- {{ ops.last_sync or "ainda não sincronizado" }}{% if ops.last_changed is not none %} · {{ ops.last_changed }} produto(s) alterado(s){% endif %}
- Sincronização agendada
- {{ ops.next_sync or ("aguardando o primeiro sync" if ops.enabled else "pausado") }}
{% if ops.rtc %}- Reforma Tributária
- {{ ops.rtc.label }}
{% endif %}- Último job
- {% if ops.last_job %}{{ ops.last_job.kind_label }} · {{ ops.last_job.status_label }}{% else %}nenhum{% endif %}
+- Processamento
- {{ "Ativo" if ops.enabled else "Pausado" }} · sincronização automática a cada {{ ops.interval_minutes }} min
- Última sincronização
- {{ ops.last_sync or "ainda não sincronizado" }}{% if ops.last_changed is not none %} · {{ ops.last_changed }} produto(s) alterado(s){% endif %}
- Sincronização agendada
- {{ ops.next_sync or ("aguardando o primeiro sync" if ops.enabled else "pausado") }}
{% if ops.rtc %}- Reforma Tributária
- {{ ops.rtc.label }}
{% endif %}{% if ops.rtc and ops.rtc.enabled %}{% if ops.rtc.products %}- Produtos RTC
- {{ ops.rtc.products.headline }}
Total {{ ops.rtc.products.total }} · com cClassTrib válido {{ ops.rtc.products.valid }} · prontos para preenchimento {{ ops.rtc.products.ready }} · ambíguos/bloqueados {{ ops.rtc.products.blocked }} {% endif %}
+- Preenchimento automático
- {{ ops.rtc.apply.state }}{% if ops.rtc.apply.applied_last_job %} · {{ ops.rtc.apply.applied_last_job }} preenchido(s) no último job{% endif %}
+
{% endif %}- Último job
- {% if ops.last_job %}{{ ops.last_job.kind_label }} · {{ ops.last_job.status_label }}{% else %}nenhum{% endif %}
Contexto da empresa
- Cliente
- {{ detail.client or "Não informado" }}
- Nome de exibição
- {{ detail.display_name or "Não informado" }}
- Hostname
- {{ detail.hostname or "Não informado" }}
- Empresa
- {{ detail.company_name or detail.company_code or "Não informado" }}
- UF
- {{ detail.company_uf or "Não informado" }}
- CRT
- {{ detail.company_crt or "Não informado" }}
- Versão do agent
- {{ detail.agent_version_display }}
- Último heartbeat
- {{ detail.last_seen_display }} · {{ detail.last_seen_age }}
- Firebird
- {{ detail.firebird_version or "Não informado" }} · ODS {{ detail.firebird_ods or "Não informado" }}
- IDs técnicos
- Agent {{ detail.technical_ids.agent_id }} · instalação {{ detail.technical_ids.installation_db_id }}
{% for event in events[:8] %}{% else %}Nenhum evento.
{% endfor %}
diff --git a/central/tests/test_cclasstrib_resolver.py b/central/tests/test_cclasstrib_resolver.py
new file mode 100644
index 0000000..07cf4e4
--- /dev/null
+++ b/central/tests/test_cclasstrib_resolver.py
@@ -0,0 +1,129 @@
+from datetime import date
+
+from central.app import rtc_reference_data as ref
+from central.app.cclasstrib_resolver import (ANNEX_DEFAULT_CLASS, annex_matches, compare_catalogs, local_catalog_hash, resolve_cclasstrib, verify_annex_class_map)
+
+TODAY = date(2026, 9, 24)
+NORMAL, SIMPLES = {"crt": "3"}, {"crt": "1"}
+ON = {"rtc_enabled": True, "local_catalog_valid": True}
+
+
+def local_from_official(skip=(), tweak=None):
+ rows = {}
+ for r in ref.OFFICIAL_CCLASSTRIB:
+ if r["code"] in skip:
+ continue
+ rows[r["code"]] = {"cst": r["cst"], "tipo_aliquota": r["tipo_aliquota"], "p_red_ibs": r["p_red_ibs"], "p_red_cbs": r["p_red_cbs"], "ind_nfe": r["ind_nfe"], "ind_nfce": r["ind_nfce"], "start": r["start"], "end": r["end"]}
+ for code, change in (tweak or {}).items():
+ rows[code] = {**rows[code], **change}
+ return rows
+
+
+def product(ncm, valid=True, code="1"):
+ return {"CODIGO": code, "CLASSIFICACAO_FISCAL": ncm, "ncm_valid": valid}
+
+
+def resolve(ncm, company=NORMAL, ctx=ON, local=None, valid=True):
+ return resolve_cclasstrib(product(ncm, valid), company, ctx, local if local is not None else local_from_official(), today=TODAY)
+
+
+def test_annex_default_class_map_is_verified_against_the_official_table():
+ assert verify_annex_class_map() == {annex: [] for annex in ANNEX_DEFAULT_CLASS}
+
+
+def test_reference_data_carries_provenance_and_the_expected_shape():
+ assert len(ref.OFFICIAL_CCLASSTRIB) == 164 and ref.OFFICIAL_CATALOG["sha256"] and ref.LC214_SOURCE["sha256"] and ref.LC214_SOURCE["accessed_at"]
+ assert {"I", "VII", "VIII", "IX", "XV"} <= set(ref.LC214_ANNEXES) and ref.LC214_ANNEXES["XIV"]["revoked"] is True
+ assert len(ref.LC214_ANNEXES["I"]["items"]) == 26 and len(ref.LC214_ANNEXES["XV"]["items"]) == 6
+
+
+def test_rtc_off_is_not_applicable_and_never_a_candidate():
+ r = resolve("10063021", ctx={"rtc_enabled": False, "local_catalog_valid": True})
+ assert r.status == "NOT_APPLICABLE" and r.rule_id == "RTC-R0" and not r.auto_apply_candidate
+
+
+def test_simples_is_insufficient_until_the_official_orientation_exists():
+ r = resolve("10063021", company=SIMPLES)
+ assert r.status == "INSUFFICIENT_EVIDENCE" and r.rule_id == "RTC-R1" and not r.auto_apply_candidate and r.source_references[-1]["document"].startswith("NT 2025.002")
+ assert resolve("10063021", company={"crt": None}).reason == "COMPANY_REGIME_UNKNOWN"
+
+
+def test_invalid_or_unconfirmed_ncm_is_insufficient():
+ assert resolve("1234", valid=True).reason == "NO_VALID_NCM"
+ assert resolve("10063021", valid=False).reason == "NO_VALID_NCM"
+
+
+def test_clean_annex_item_resolves_to_the_annex_default_class_with_evidence():
+ r = resolve("10063021") # rice: Anexo I item 1 (subposicao 1006.30)
+ assert r.status == "RESOLVED_WITH_EXPLICIT_RULE" and r.resolved_cclasstrib == "200003" and r.resolved_cst_ibscbs == "200" and r.rule_id == "RTC-R3" and r.auto_apply_candidate
+ assert r.evidence[0]["annex"] == "I" and r.evidence[0]["clean"] is True and r.confidence_type == "ANNEX_TEXT_MATCH"
+ assert r.source_references[0]["sha256"] == ref.LC214_SOURCE["sha256"] and r.inputs_used["ncm"] == "10063021"
+
+
+def test_conditional_annex_item_is_ambiguous_not_guessed():
+ milk = next(i for i in ref.LC214_ANNEXES["I"]["items"] if not i["clean"] and i["prefixes"])
+ ncm = milk["prefixes"][0].ljust(8, "0")
+ r = resolve(ncm)
+ assert r.status == "AMBIGUOUS" and r.rule_id == "RTC-A1" and not r.auto_apply_candidate and r.evidence[0]["clean"] is False
+
+
+def test_annex_without_a_unique_default_class_is_ambiguous():
+ item = next(i for i in ref.LC214_ANNEXES["IV"]["items"] if i["clean"]) # medical devices: 60% class vs zero-rated public-buyer class
+ r = resolve(item["prefixes"][0].ljust(8, "1"))
+ assert r.status == "AMBIGUOUS" and "NEEDS_OPERATION_OR_CONDITION" in r.reason
+
+
+def test_revoked_annex_only_is_ambiguous():
+ prefix = next(p for i in ref.LC214_ANNEXES["XIV"]["items"] for p in i["prefixes"] if len(p) == 8 and not annex_matches_other_than_xiv(p))
+ assert resolve(prefix).rule_id == "RTC-A1" and resolve(prefix).reason == "LISTED_ONLY_IN_REVOKED_ANNEX"
+
+
+def annex_matches_other_than_xiv(prefix):
+ return [h for h in annex_matches(prefix) if h["annex"] != "XIV"]
+
+
+def test_nature_based_chapters_are_ambiguous():
+ for ncm in ("03028990", "30049099", "27101259", "49019900", "87032100", "90183100"):
+ r = resolve(ncm)
+ assert r.status == "AMBIGUOUS" and r.rule_id in ("RTC-A3", "RTC-A1", "RTC-A2"), ncm
+
+
+def test_residual_ncm_outside_every_annex_and_sensitive_chapter_is_integral_taxation():
+ r = resolve("39235000") # plastic closures: no annex, no nature-based regime
+ assert r.status == "RESOLVED_WITH_EXPLICIT_RULE" and r.resolved_cclasstrib == "000001" and r.resolved_cst_ibscbs == "000" and r.rule_id == "RTC-R4" and r.confidence_type == "EXCLUSION_OF_ALL_SPECIAL_REGIMES"
+ assert r.auto_apply_candidate and annex_matches("39235000") == []
+
+
+def test_a_class_missing_or_different_in_the_local_catalog_is_never_proposed():
+ r = resolve("39235000", local=local_from_official(skip=("000001",)))
+ assert r.status == "INSUFFICIENT_EVIDENCE" and r.reason == "CLASS_NOT_IN_LOCAL_CATALOG" and not r.auto_apply_candidate
+ r2 = resolve("39235000", local=local_from_official(tweak={"000001": {"cst": "010"}}))
+ assert r2.reason == "LOCAL_OFFICIAL_MISMATCH" and not r2.auto_apply_candidate
+ r3 = resolve("10063021", local=local_from_official(tweak={"200003": {"ind_nfe": False, "ind_nfce": False}}))
+ assert r3.reason == "LOCAL_OFFICIAL_MISMATCH"
+
+
+def test_invalid_local_catalog_blocks_every_proposal():
+ assert resolve("39235000", ctx={"rtc_enabled": True, "local_catalog_valid": False}).reason == "LOCAL_RTC_CATALOG_INVALID"
+
+
+def test_catalog_comparison_classifies_every_code_and_flags_material_problems():
+ full = compare_catalogs(local_from_official(), TODAY)
+ assert full["counts"]["MATCH"] == 161 and full["counts"]["EXPIRED"] == 3 and full["compatibility"] == "PARTIAL_LOCAL_OUTDATED" # 220001-3 ended on 2026-01-01
+ assert compare_catalogs(local_from_official(skip=("220001", "220002", "220003")), TODAY)["compatibility"] == "FULL"
+ outdated = compare_catalogs(local_from_official(skip=("000005", "200053")), TODAY)
+ assert outdated["counts"]["OFFICIAL_ONLY"] == 2 and outdated["compatibility"] == "PARTIAL_LOCAL_OUTDATED" and outdated["counts"]["MISMATCH"] == 0
+ local = local_from_official(tweak={"200003": {"p_red_ibs": "60"}})
+ local["999999"] = {"cst": "000", "p_red_ibs": "0", "p_red_cbs": "0", "ind_nfe": True, "ind_nfce": True}
+ bad = compare_catalogs(local, TODAY)
+ assert bad["per_code"]["200003"] == "MISMATCH" and bad["per_code"]["999999"] == "LOCAL_ONLY" and bad["compatibility"] == "MATERIAL_MISMATCH"
+
+
+def test_local_catalog_hash_is_stable_and_sensitive():
+ a, b = local_from_official(), local_from_official(tweak={"200003": {"p_red_ibs": "60"}})
+ assert local_catalog_hash(a) == local_catalog_hash(local_from_official()) and local_catalog_hash(a) != local_catalog_hash(b)
+
+
+def test_resolution_is_deterministic_and_auditable():
+ a, b = resolve("10063021"), resolve("10063021")
+ assert a.as_dict() == b.as_dict() and {"rule_id", "inputs_used", "source_references", "evidence", "reason"} <= set(a.as_dict())
diff --git a/central/tests/test_control_panel_pages.py b/central/tests/test_control_panel_pages.py
index 1a53e1c..c69253f 100644
--- a/central/tests/test_control_panel_pages.py
+++ b/central/tests/test_control_panel_pages.py
@@ -587,3 +587,45 @@ def test_rtc_status_shows_where_and_when_the_agent_observed_it():
assert "linhas de PARAMETROS divergentes" in conflict and ">Desativada<" in conflict
for legacy in ("Escopo anterior", "Escopo ampliado", "Legacy coverage", "Expanded coverage"):
assert legacy not in conflict
+
+
+# ---------------------------------------------------------------- RTC auto-apply authorization (central, default OFF)
+def _installation(client, agent_id):
+ from central.app.models import Installation as Inst
+ with client._session_factory() as session:
+ row = session.scalar(select(Inst).where(Inst.agent_id == agent_id))
+ return bool(row.rtc_auto_apply_authorized)
+
+
+def test_rtc_auto_apply_authorization_is_off_by_default_and_needs_csrf_and_a_typed_confirmation():
+ client, agent_id, _ = _panel_client()
+ assert _installation(client, agent_id) is False
+ csrf = client.cookies.get("gti_csrf")
+ url = f"/agents/{agent_id}/rtc-auto-apply"
+ assert client.post(url, data={"csrf_token": "wrong", "decision": "authorize", "confirm": "PREENCHER"}).status_code == 403
+ assert client.post(url, data={"csrf_token": csrf, "decision": "authorize"}).status_code == 422
+ assert client.post(url, data={"csrf_token": csrf, "decision": "authorize", "confirm": "sim"}).status_code == 422
+ assert _installation(client, agent_id) is False
+ assert client.post(url, data={"csrf_token": csrf, "decision": "authorize", "confirm": "preencher"}, follow_redirects=False).status_code == 303
+ assert _installation(client, agent_id) is True
+ assert client.post(url, data={"csrf_token": csrf, "decision": "revoke"}, follow_redirects=False).status_code == 303
+ assert _installation(client, agent_id) is False
+ assert client.post(url, data={"csrf_token": csrf, "decision": "other"}).status_code == 422
+ from central.app.models import AuditEvent
+ with client._session_factory() as session:
+ actions = [a.action for a in session.scalars(select(AuditEvent).order_by(AuditEvent.id)).all() if a.action.startswith("RTC_AUTO_APPLY")]
+ assert actions == ["RTC_AUTO_APPLY_AUTHORIZE", "RTC_AUTO_APPLY_REVOKE"]
+
+
+def test_panel_shows_rtc_products_summary_and_the_pending_message_only_when_rtc_is_on():
+ client, agent_id, _ = _panel_client()
+ _complete_sync(client, agent_id, {"rtc_enabled": False, "rtc_supported": True, "rtc_resolution": None})
+ off = client.get(f"/agents/{agent_id}").text
+ assert "Produtos RTC" not in off and "cClassTrib pendente" not in off and "Preenchimento automático" not in off
+ resolution = {"total": 521, "valid_existing": 0, "ready_to_apply": 280, "ambiguous": 215, "insufficient": 26, "catalog_compatibility": {"compatibility": "PARTIAL_LOCAL_OUTDATED"}}
+ _complete_sync(client, agent_id, {"rtc_enabled": True, "rtc_supported": True, "rtc_catalog_valid": True, "rtc_resolution": resolution})
+ on = client.get(f"/agents/{agent_id}").text
+ assert "Reforma Tributária ativa — cClassTrib pendente em 521 produtos" in on and "prontos para preenchimento 280" in on and "ambíguos/bloqueados 241" in on
+ assert "Preenchimento automático" in on and "Desativado" in on and "digite PREENCHER" in on
+ for legacy in ("Escopo anterior", "Escopo ampliado"):
+ assert legacy not in on
diff --git a/central/tests/test_health.py b/central/tests/test_health.py
index 7d4b9c1..978c1ad 100644
--- a/central/tests/test_health.py
+++ b/central/tests/test_health.py
@@ -17,7 +17,7 @@ def test_health_is_unavailable_when_database_is_down():
def test_version_endpoint_reports_release_and_fiscal_versions():
body = TestClient(create_app(database_probe=lambda: True)).get("/version").json()
- assert body["version"] == "1.1.8" and body["api_compat"] == "1.0" and body["engine_version"] and body["decision_version"]
+ assert body["version"] == "1.1.9" and body["api_compat"] == "1.0" and body["engine_version"] and body["decision_version"]
def test_production_refuses_the_dev_token(monkeypatch):
diff --git a/central/tests/test_zero_touch_hub.py b/central/tests/test_zero_touch_hub.py
index 26f87a8..1f91f17 100644
--- a/central/tests/test_zero_touch_hub.py
+++ b/central/tests/test_zero_touch_hub.py
@@ -264,3 +264,46 @@ def test_rtc_on_then_off_and_pis_fix_leave_no_stale_open_blockers_and_never_dupl
with Session(engine) as s:
rows = s.scalars(select(BlockedProduct)).all()
assert len(rows) == 2 and [(r.product_code, r.resolved_at is None) for r in rows] == [("20", True), ("21", False)]
+
+
+def test_job_carries_the_central_rtc_authorization_default_off_and_follows_the_installation():
+ client, engine = _client()
+ hb(client)
+ job = client.get("/v1/jobs/next", headers=H).json()
+ assert job["authorizations"] == {"rtc_auto_apply": False} # never on by default
+ client.post(f"/v1/jobs/{job['job_id']}/complete", json={"result_summary": {}}, headers=H)
+ with Session(engine) as s:
+ inst = s.scalars(select(Installation)).one()
+ inst.rtc_auto_apply_authorized = True
+ s.commit()
+ age_last_sync(engine, 4000)
+ hb(client)
+ assert client.get("/v1/jobs/next", headers=H).json()["authorizations"] == {"rtc_auto_apply": True}
+
+
+def test_rtc_write_audits_are_persisted_with_server_side_identity_and_never_duplicated_per_job():
+ from central.app.models import AgentEvent, RtcWriteAudit
+ client, engine = _client()
+ hb(client)
+ applied = {"outcome": "APPLIED", "product_code": "10", "field": "CCLASSTRIB", "old_value": None, "new_value": "200003", "rule_id": "RTC-R3", "evidence": {"reason": "ANNEX_I_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS"},
+ "official_source_version": {"cclasstrib_sha256": "ab" * 32}, "local_catalog_hash": "cd" * 32, "timestamp": "2026-09-24T20:00:00+00:00", "job_id": 999, "tenant_id": 12345, "agent_id": 777}
+ aborted = {"outcome": "ABORTED", "product_code": "11", "field": "CCLASSTRIB", "reason": "RTC_NO_LONGER_ENABLED", "rule_id": "RTC-R4", "timestamp": "2026-09-24T20:00:01+00:00"}
+ other_field = {"outcome": "APPLIED", "product_code": "12", "field": "IPI", "new_value": "1.0"} # anything but CCLASSTRIB is refused
+ finish(client, engine, {"operational": OPERATIONAL, "blocked_products": [], "resolved_products": [], "rtc_auto_apply": {"mode": "AUTO_APPLY", "applied": [applied, other_field], "aborted": [aborted], "aborted_reasons": {"RTC_NO_LONGER_ENABLED": 1}}})
+ with Session(engine) as s:
+ rows = s.scalars(select(RtcWriteAudit).order_by(RtcWriteAudit.id)).all()
+ assert [(r.product_code, r.outcome, r.old_value, r.new_value, r.rule_id) for r in rows] == [("10", "APPLIED", None, "200003", "RTC-R3"), ("11", "ABORTED", None, None, "RTC-R4")]
+ inst = s.scalars(select(Installation)).one()
+ assert all(r.installation_id == inst.id and r.agent_id == inst.agent_id and r.tenant_id == inst.tenant_id for r in rows) # identity comes from the authenticated context, not the payload
+ assert rows[0].local_catalog_hash == "cd" * 32 and rows[0].official_source_version["cclasstrib_sha256"] == "ab" * 32 and rows[0].job_id != 999
+ events = [e for e in s.scalars(select(AgentEvent)).all() if e.event_type == "RTC_AUTO_APPLY"]
+ assert len(events) == 1 and events[0].structured_context["applied"] == 1 and events[0].severity == "WARNING"
+
+
+def test_report_only_jobs_leave_no_audit_rows():
+ from central.app.models import RtcWriteAudit
+ client, engine = _client()
+ hb(client)
+ finish(client, engine, {"operational": OPERATIONAL, "blocked_products": [], "resolved_products": [], "rtc_auto_apply": {"mode": "REPORT_ONLY", "applied": [], "aborted": [], "ready_total": 280}})
+ with Session(engine) as s:
+ assert s.scalars(select(RtcWriteAudit)).all() == []
diff --git a/deploy/agent-windows/agent.env.template b/deploy/agent-windows/agent.env.template
index 2e2169b..1c403f7 100644
--- a/deploy/agent-windows/agent.env.template
+++ b/deploy/agent-windows/agent.env.template
@@ -19,4 +19,4 @@ FB_PASSWORD=
FISCAL_MODE=DRY_RUN
FIREBIRD_WRITES=0
POLL_INTERVAL_SECONDS=5
-AGENT_VERSION=1.1.8
+AGENT_VERSION=1.1.9
diff --git a/deploy/agent-windows/gti-agent.ps1 b/deploy/agent-windows/gti-agent.ps1
index 8978b66..91a6b33 100644
--- a/deploy/agent-windows/gti-agent.ps1
+++ b/deploy/agent-windows/gti-agent.ps1
@@ -164,7 +164,7 @@ switch ($Command) {
"GTI_HUB_URL=$hub", "AGENT_TOKEN=$token", "AGENT_ID=$agentId",
"COMPANY_CODE=$code", "COMPANY_CNPJ=$cnpj", "COMPANY_CRT_SOURCE=$crtSource",
"FIREBIRD_DATABASE_PATH=$db", "FB_USER=$fbUser", "FB_PASSWORD=$fbPass",
- 'FISCAL_MODE=DRY_RUN', 'FIREBIRD_WRITES=0', 'POLL_INTERVAL_SECONDS=5', 'AGENT_VERSION=1.1.8'
+ 'FISCAL_MODE=DRY_RUN', 'FIREBIRD_WRITES=0', 'POLL_INTERVAL_SECONDS=5', 'AGENT_VERSION=1.1.9'
)
Set-Content -Path $EnvFile -Value $lines -Encoding UTF8
}
diff --git a/deploy/agent-windows/pilot-construcao.env.example b/deploy/agent-windows/pilot-construcao.env.example
index b45b1e4..eb14d67 100644
--- a/deploy/agent-windows/pilot-construcao.env.example
+++ b/deploy/agent-windows/pilot-construcao.env.example
@@ -19,4 +19,4 @@ FB_PASSWORD=
FISCAL_MODE=DRY_RUN
FIREBIRD_WRITES=0
POLL_INTERVAL_SECONDS=5
-AGENT_VERSION=1.1.8
+AGENT_VERSION=1.1.9
diff --git a/deploy/agent-windows/profiles/mmmodas.env.example b/deploy/agent-windows/profiles/mmmodas.env.example
index 4bd52b2..6b36fbd 100644
--- a/deploy/agent-windows/profiles/mmmodas.env.example
+++ b/deploy/agent-windows/profiles/mmmodas.env.example
@@ -19,4 +19,4 @@ FB_PASSWORD=
FISCAL_MODE=DRY_RUN
FIREBIRD_WRITES=0
POLL_INTERVAL_SECONDS=5
-AGENT_VERSION=1.1.8
+AGENT_VERSION=1.1.9
diff --git a/deploy/agent-windows/profiles/rincao.env.example b/deploy/agent-windows/profiles/rincao.env.example
index 8ebe9d1..1cffc9e 100644
--- a/deploy/agent-windows/profiles/rincao.env.example
+++ b/deploy/agent-windows/profiles/rincao.env.example
@@ -19,4 +19,4 @@ FB_PASSWORD=
FISCAL_MODE=DRY_RUN
FIREBIRD_WRITES=0
POLL_INTERVAL_SECONDS=5
-AGENT_VERSION=1.1.8
+AGENT_VERSION=1.1.9
diff --git a/deploy/agent-windows/profiles/uniao.env.example b/deploy/agent-windows/profiles/uniao.env.example
index 0a0d163..5a9f85a 100644
--- a/deploy/agent-windows/profiles/uniao.env.example
+++ b/deploy/agent-windows/profiles/uniao.env.example
@@ -19,4 +19,4 @@ FB_PASSWORD=
FISCAL_MODE=DRY_RUN
FIREBIRD_WRITES=0
POLL_INTERVAL_SECONDS=5
-AGENT_VERSION=1.1.8
+AGENT_VERSION=1.1.9
diff --git a/deploy/hub/.env.example b/deploy/hub/.env.example
index 8b96c12..4ffd04c 100644
--- a/deploy/hub/.env.example
+++ b/deploy/hub/.env.example
@@ -1,5 +1,5 @@
# GTI Fiscal Hub — production environment (copy to .env, never commit .env)
-GTI_FISCAL_VERSION=1.1.8
+GTI_FISCAL_VERSION=1.1.9
# REQUIRED. URL-safe secret (used inside a connection URL): openssl rand -hex 24
POSTGRES_PASSWORD=
diff --git a/deploy/hub/docker-compose.prod.yml b/deploy/hub/docker-compose.prod.yml
index 7876fa8..af693b3 100644
--- a/deploy/hub/docker-compose.prod.yml
+++ b/deploy/hub/docker-compose.prod.yml
@@ -36,7 +36,7 @@ services:
build:
context: ../..
dockerfile: central/Dockerfile
- image: gti-fiscal-hub:${GTI_FISCAL_VERSION:-1.1.8}
+ image: gti-fiscal-hub:${GTI_FISCAL_VERSION:-1.1.9}
restart: unless-stopped
depends_on:
postgres:
diff --git a/docs/DEPLOY_HUB.md b/docs/DEPLOY_HUB.md
index 8857277..919eaf5 100644
--- a/docs/DEPLOY_HUB.md
+++ b/docs/DEPLOY_HUB.md
@@ -16,7 +16,7 @@ A variável de ambiente `GTI_SSH_PASSWORD`, se existir, tem prioridade. A senha
## Deploy
```
powershell -ExecutionPolicy Bypass -File .\scripts\deploy_hub.ps1
-powershell -ExecutionPolicy Bypass -File .\scripts\deploy_hub.ps1 -PublishAgent -Version 1.1.8
+powershell -ExecutionPolicy Bypass -File .\scripts\deploy_hub.ps1 -PublishAgent -Version 1.1.9
```
Parâmetros: `-Version` (padrão `release/VERSION`), `-PublishAgent`, `-SkipTests`, `-DryRun`.
diff --git a/docs/cclasstrib_resolution.md b/docs/cclasstrib_resolution.md
new file mode 100644
index 0000000..16fc979
--- /dev/null
+++ b/docs/cclasstrib_resolution.md
@@ -0,0 +1,67 @@
+# Determinação segura do cClassTrib (resolver determinístico)
+
+`central/app/cclasstrib_resolver.py` (puro, sem Firebird, sem rede, sem probabilidade) + `central/app/rtc_reference_data.py` (gerado por `scripts/build_rtc_reference_data.py`, com hash).
+`ACCESSED_AT`: **2026-09-24/25**. Nada aqui é chute: uma classe só é proposta quando uma regra **explícita**, ancorada nos textos oficiais, a prova.
+
+## Fontes oficiais (SOURCE / DOCUMENT / VERSION / PUBLICATION / SHA256)
+| Fonte | Documento | Versão / publicação | SHA256 |
+|---|---|---|---|
+| Portal Nacional NF-e (ENCAT) | Tabela **cClassTrib** (164 classes, 18 CST) — `cClassTrib 2026-06-22.xlsx` | publicada 22/06/2026; no repo em `sources/raw/bootstrap_v1/` e no Hub (dataset `RTC_CCLASSTRIB` ACTIVE) | `1448cb63a41bdb67…` |
+| Planalto (cópia do Internet Archive; planalto.gov.br recusa conexão direta) | **LC 214/2025 compilada** (com LC 227/2026: Anexo XIV revogado) — arts. 125–152 (reduções), 172 (combustíveis), 348 (2026); Anexos I–XV | acessado 2026-09-24 | `5c7d59b3c49e5b7c…` |
+| Portal Nacional NF-e | **NT 2025.002-RTC v1.51** (04/08/2026) — para CRT 1/2/4 as orientações de IBS/CBS "serão publicadas em NT futura"; tributação a partir de 2027 (LC 214 art. 348) | `https://www.nfe.fazenda.gov.br/portal/exibirArquivo.aspx?conteudo=AKD/muSmiIY=` | ver `docs/sources/SOURCES_MANIFEST_UNIFIED_FISCAL_V1.json` |
+| SGV 5.1.0.4 (executável) | tela de produto: `cClassTrib` = `TRzDBButtonEdit` `DataField=CCLASSTRIB`; consulta `select * from RTC_CCLASSTRIB where … (IND_NFE=1 or IND_NFCE=1 or IND_CTE=1)`; junção do documento `C000025.CCLASSTRIB → RTC_CCLASSTRIB → RTC_CST` | binário local | — |
+
+O portal NF-e foi rastreado (Documentos, Diversos, Atos): não expõe tabela cClassTrib mais nova que 22/06/2026. Não há endpoint oficial NCM→cClassTrib: o vínculo vem dos **Anexos da LC 214** (listas de NCM) + tabela oficial.
+
+## O que o SGV faz (item 5) — DOCUMENT_CCLASSTRIB_SOURCE
+O SGV **não tem** regra produto→cClassTrib: o operador escolhe a classe pelo botão de busca (filtrada por `IND_NFE/IND_NFCE/IND_CTE=1`) e o documento usa `C000025.CCLASSTRIB` diretamente, juntando ao catálogo local e ao CST. Nenhuma trigger/procedure referencia RTC; `USAR_REFORMA_TRIBUTARIA` só liga/desliga. Consequência: qualquer resolução automática é regra **nossa**, portanto tem de ser provada e auditável. A classe proposta tem de passar no mesmo filtro do SGV (usável em NF-e/NFC-e).
+
+## Catálogo local × oficial (item 4) — RTC_LOCAL_OFFICIAL_COMPATIBILITY
+Comparação por código (CST, reduções IBS/CBS, indicadores NF-e/NFC-e, vigência): `MATCH | LOCAL_ONLY | OFFICIAL_ONLY | MISMATCH | EXPIRED`. Nada é escrito no catálogo local.
+
+| | TESTESOFICIAIS (= todos os bancos com RTC, mesmo catálogo) |
+|---|---|
+| MATCH | 131 |
+| OFFICIAL_ONLY (local desatualizado) | 19 (`000005, 200053, 200054, 221002-4, 400002, 410032-7, 550022-5, 620007, 820009`) |
+| MISMATCH | 11 — só `DOCUMENT_FLAGS` (IND_NFE/IND_NFCE): `200001, 200044, 410027, 410028, 410031, 550002, 620001-5` |
+| EXPIRED presentes no local | 3 (`220001-3`, fim 01/01/2026) |
+| LOCAL_ONLY | 0 |
+
+Conclusão: **LOCAL_CATALOG_HAS_ENOUGH_METADATA_TO_RESOLVE = false**. O catálogo local (33 colunas: CST, tipo de alíquota, reduções, indicadores de documento, monofasia, `ANEXO`, `LINK`) descreve *a classe*, não contém NCM nem critério de produto: só o `ANEXO` liga classe a anexo. A determinação usa o catálogo local **para validar** e os Anexos da LC 214 **para decidir**. Incompatibilidade material ⇒ só a classe afetada é bloqueada (`RTC_LOCAL_CATALOG_OUTDATED` / `CCLASSTRIB_OFFICIAL_MISMATCH`); as classes que as regras usam (`000001, 200003, 200014, 200034, 200035`) são `MATCH`.
+
+## Modelo de resolução e regras
+Premissa documentada: **venda ordinária no mercado interno** (default de produto). Classes que dependem do adquirente/operação (órgão público, exportação, ZFM/ALC, crédito presumido, diferimento…) não cabem num default de produto ⇒ `AMBIGUOUS`.
+
+| Regra | Condição | Status |
+|---|---|---|
+| RTC-R0 | RTC desligada no ERP | `NOT_APPLICABLE` |
+| RTC-G1 | catálogo RTC local com falha de integridade | `INSUFFICIENT_EVIDENCE` |
+| RTC-R1 | Simples (CRT 1/2/4) ou regime desconhecido | `INSUFFICIENT_EVIDENCE` (NT 2025.002: orientação pendente) |
+| RTC-R2 | NCM sem confirmação de 8 dígitos válidos | `INSUFFICIENT_EVIDENCE` |
+| RTC-A1 | NCM em anexo revogado, em anexo sem classe-padrão única (IV, V, VI, IX, X, XI, XII, XIII…) ou sob texto condicional ("exceto", "em conformidade com…", "ressalvados…") | `AMBIGUOUS` |
+| RTC-A2 | NCM listado em mais de um anexo | `AMBIGUOUS` |
+| RTC-A3 | capítulos 01–14, 27, 30, 49, 71, 87, 88, 89, 90 e posições 9619, 2207, 3826, 8703: regime definido pela natureza/operação do bem | `AMBIGUOUS` |
+| RTC-R3 | NCM em **exatamente um** anexo com classe-padrão única (I→`200003`, VII→`200034`, VIII→`200035`, XV→`200014`) e item sem condição | `RESOLVED_WITH_EXPLICIT_RULE` |
+| RTC-R4 | NCM em **nenhum** anexo e fora dos capítulos acima ⇒ tributação integral (regra geral, LC 214 art. 4) | `RESOLVED_WITH_EXPLICIT_RULE` → `000001` |
+| RTC-G2 | classe proposta ausente/diferente no catálogo local, fora de vigência ou inutilizável em NF-e/NFC-e | `INSUFFICIENT_EVIDENCE` |
+
+`RESOLVED_DETERMINISTIC` (regra sem premissa de operação) não é usado: toda resolução carrega a premissa "venda ordinária" e por isso é `RESOLVED_WITH_EXPLICIT_RULE`.
+Saída auditável: `status, resolved_cclasstrib, resolved_cst_ibscbs, reason, rule_id, confidence_type` (`ANNEX_TEXT_MATCH` | `EXCLUSION_OF_ALL_SPECIAL_REGIMES`; sem score), `inputs_used`, `evidence` (item do anexo, prefixo, texto), `source_references` (sha256).
+O anexo é lido do texto oficial por `scripts/build_rtc_reference_data.py` (item a item; `clean=False` quando há condição). `verify_annex_class_map()` prova contra a tabela oficial que cada classe-padrão existe, é a única classe do anexo usável em NF-e/NFC-e e tem o `ANEXO` esperado (o Anexo IX ficou de fora: a classe `515001` é irmã).
+
+## Blockers RTC (uma causa raiz, um blocker por produto)
+`CCLASSTRIB_MISSING` (com `READY_TO_APPLY::` quando a regra prova a classe) · `CCLASSTRIB_MISSING_UNRESOLVED` (cClassTrib não determinado) · `CCLASSTRIB_AMBIGUOUS` (cClassTrib ambíguo) · `RTC_RULE_EVIDENCE_MISSING` (evidência fiscal insuficiente) · `RTC_LOCAL_CATALOG_OUTDATED` (catálogo RTC local incompatível) · `CCLASSTRIB_OFFICIAL_MISMATCH` (classe existente diverge do oficial) · `CCLASSTRIB_CONFLICT` (valor existente ≠ regra determinística) + os de validação (`INVALID_FORMAT`, `NOT_IN_CATALOG`, `RTC_CST_MISSING`, `RTC_CATALOG_INVALID`). Todos vão para a mesma fila (categoria `RTC`).
+
+## Dry-run real (somente leitura; `scripts/rtc_resolution_dryrun.py` → `docs/runs/rtc_resolution_dryrun.json`, amostra de 100 em `docs/runs/rtc_resolution_audit_sample.csv`)
+Estado como está hoje: TESTESOFICIAIS e CONSTRUCAO têm RTC ligada e regime Simples ⇒ **0 candidatos** (RTC-R1). Simulação "regime normal + RTC ligada" (o que as regras resolveriam quando existir orientação oficial para Simples):
+
+| Banco | Produtos | Prontos (R3+R4) | Ambíguos | Insuficientes (NCM inválido) |
+|---|---|---|---|---|
+| TESTESOFICIAIS | 521 | 280 | 215 | 26 |
+| CONSTRUCAO | 3.712 | 2.725 | 973 | 14 |
+| MMMODAS | 20.996 | 20.831 | 49 | 116 |
+| RINCAO (CRT 3, RTC off no banco) | 894 | 530 | 364 | 0 |
+| UNIAO | 8.942 | 7.419 | 1.432 | 91 |
+
+## Limitações
+Simples fica bloqueado até haver orientação oficial (ou decisão explícita de empresa, não implementada); operações especiais não são cobertas pelo default de produto; a extração dos anexos é textual (itens condicionais viram ambíguos de propósito); o catálogo oficial usado é o de 22/06/2026; sem autorização, nada é escrito (ver `docs/rtc_auto_apply.md`).
diff --git a/docs/rtc_auto_apply.md b/docs/rtc_auto_apply.md
new file mode 100644
index 0000000..43c431f
--- /dev/null
+++ b/docs/rtc_auto_apply.md
@@ -0,0 +1,32 @@
+# Preenchimento automático do cClassTrib (RTC auto-apply)
+
+Código: `agent/src/gti_fiscal_agent/rtc_auto_apply.py` · integração `agent/scripts/run_agent_service.py::_rtc_auto_apply` · Hub `central/app/rtc_audit.py`, migração `0027_rtc_auto_apply`, rota `POST /agents/{id}/rtc-auto-apply`.
+**Estado de entrega: mecanismo pronto, DESLIGADO em todo lugar. Nenhuma escrita em banco real foi feita ou é possível sem as três chaves abaixo.**
+
+## Escopo de escrita
+Uma coluna: `C000025.CCLASSTRIB`. `ALLOWED_RTC_WRITE_FIELDS = ["CCLASSTRIB"]`; o SQL é uma constante (`UPDATE C000025 SET CCLASSTRIB = ? WHERE CODIGO = ? AND (CCLASSTRIB IS NULL OR TRIM(CCLASSTRIB) = '')`). Não há write genérico de produto, nem escrita em NFCE/itens/catálogo RTC.
+Só candidatos `RESOLVED_*` (ver `docs/cclasstrib_resolution.md`) com `CCLASSTRIB` vazio e nenhum outro problema RTC. Nunca sobrescreve: valor igual ⇒ `NO_WRITE_REQUIRED`; valor diferente ⇒ blocker `CCLASSTRIB_CONFLICT` (a política de correção precisa de aprovação futura).
+
+## Três chaves (todas necessárias; padrão = fechadas)
+1. `FIREBIRD_WRITES` efetivo no Agent (`FISCAL_MODE=AUTO_APPLY` + caminho/esquema autorizados — as travas já existentes);
+2. `RTC_AUTO_APPLY_ENABLED=1` no `agent.env` (chave própria; `RTC_AUTO_APPLY_MAX_PER_JOB`, padrão 500, limita o raio de ação);
+3. autorização do **Hub** por instalação (`installations.rtc_auto_apply_authorized`, padrão `false`), entregue com cada job (`authorizations.rtc_auto_apply`) e alterada só pelo painel: botão "Autorizar" exige CSRF e digitar `PREENCHER`; toda mudança gera `audit_events` (`RTC_AUTO_APPLY_AUTHORIZE/REVOKE`).
+Sem as três: modo `REPORT_ONLY` (conta candidatos, abre nenhuma conexão de escrita). O Agent reporta a capability `rtc_auto_apply` no heartbeat.
+
+## Proteção contra decisão velha (por produto, uma transação curta)
+Imediatamente antes do UPDATE o Agent **relê tudo do banco**: parâmetro `USAR_REFORMA_TRIBUTARIA` (todas as linhas; divergência ⇒ aborta), integridade do catálogo, hash do catálogo (deve ser o da decisão), a linha do produto (única; NCM igual ao da decisão; `CCLASSTRIB` ainda vazio) e **re-deriva** a resolução com dados novos (mesma classe e mesma regra). Qualquer diferença ⇒ `ABORTED` daquele produto (`RTC_NO_LONGER_ENABLED`, `RTC_CATALOG_INVALID`, `LOCAL_CATALOG_CHANGED_SINCE_DECISION`, `PRODUCT_CHANGED_NCM`, `VALUE_ALREADY_SET_NEVER_OVERWRITTEN`, `NO_WRITE_REQUIRED`, `DECISION_CHANGED`, `PRODUCT_ROW_NOT_UNIQUE`, `UPDATE_ROWCOUNT_NOT_ONE`). `rowcount` deve ser 1; releitura confirma o valor; a FK física `C000025.CCLASSTRIB → RTC_CCLASSTRIB` é a segunda barreira. Falha de um produto não interrompe os demais.
+Idempotência: com o valor correto gravado o produto deixa de ser candidato (`valid_existing`); segunda execução = 0 escritas.
+
+## Auditoria e rollback lógico
+Cada tentativa vira uma linha em `rtc_write_audits` (append-only): `tenant/installation/agent` (do contexto autenticado, nunca do payload), `client`, `job_id`, `product_code`, `field`, `outcome` (`APPLIED|ABORTED|FAILED`), `reason`, **`old_value`** (sempre nulo hoje: só se preenche campo vazio), `new_value`, `rule_id`, `evidence` (regra, entradas, item do anexo), `official_source_version` (data + sha256 da tabela cClassTrib e sha256 da LC 214), `local_catalog_hash`, `written_at`. Um resumo vai como evento `RTC_AUTO_APPLY` (severidade WARNING quando houve escrita). Reverter = `UPDATE C000025 SET CCLASSTRIB = NULL` para os `product_code` do `job_id` (não há botão de rollback nesta versão).
+
+## Painel
+Mesmo painel, mesma fila. No detalhe do Agent, com RTC ativa: "Reforma Tributária ativa — cClassTrib pendente em N produtos", "Produtos RTC: total · válidos · prontos para preenchimento · ambíguos/bloqueados", estado do preenchimento automático ("Desativado / Autorizado no Hub, aguardando o Agent (…) / Ativo") e o formulário de autorização. RTC desligada não mostra nada disto.
+
+## Validação
+- Testes: `agent/tests/test_rtc_auto_apply.py` (gates, candidatos, escrita restrita, idempotência, RTC desligada entre decisão e escrita, catálogo alterado/inválido, NCM alterado, valor existente, duplicata, limite por job), `central/tests/test_zero_touch_hub.py`, `central/tests/test_control_panel_pages.py`, `tests/test_rtc_copy_write_guard.py`.
+- **E2E de escrita em CÓPIA descartável** (`scripts/rtc_copy_write_e2e.py`; cópia `scratch_rtc_e2e/TESTESOFICIAIS_RTC_COPY.FDB` via gbak; o script recusa qualquer outro caminho): empresa da cópia trocada para regime normal (CRT 3) como experimento; 280 candidatos → 280 escritas verificadas (`000001`×203, `200034`×75, `200014`×2), somente a coluna `CCLASSTRIB` mudou (diff da tabela inteira), 0 órfãos de FK/CST, catálogo RTC local intacto (145 linhas antes e depois), cobertura da cópia 0% → 53,55%; decisão velha (RTC desligada na cópia entre decisão e escrita) → 280 abortos, 0 escritas; segunda execução → 0 candidatos, 0 escritas. Resultado em `docs/runs/rtc_copy_write_e2e.json`.
+- Bancos reais: 0 escritas, 0 tentativas.
+
+## Limitações
+Simples continua bloqueado (sem orientação oficial); `CCLASSTRIB_CONFLICT` só reporta; não há rollback automático; o texto dos anexos é interpretado de forma conservadora (condição ⇒ ambíguo). Para o piloto real: escolher uma instalação em regime normal com RTC ligada, ligar as três chaves e revisar a amostra de auditoria antes.
diff --git a/docs/rtc_pis_cofins_model.md b/docs/rtc_pis_cofins_model.md
index f017490..773b8a6 100644
--- a/docs/rtc_pis_cofins_model.md
+++ b/docs/rtc_pis_cofins_model.md
@@ -49,5 +49,8 @@ O fingerprint dos blockers inclui o estado RTC: 0→1 cria blockers novos; 1→0
Estado atual do parâmetro nas cópias locais: `CONSTRUCAO=1`, `TESTESOFICIAIS=1`, `MMMODAS=0`, `RINCAO=0`, `UNIAO=0` (cada uma com **uma** linha em `PARAMETROS`, `ODS 11.2`, Firebird 2.5.9). O discovery de `TESTESOFICIAIS.FDB` registrou `0` às 15:25 de 24/09 e a leitura de hoje (mesmo arquivo, mesmas 521 linhas) retorna `1`. Causas descartadas: linha errada / várias linhas (há 1), cache do Hub (a leitura é direta no Firebird, o Agent lê ao vivo), outro arquivo (mesmo caminho canônico). Causa real comprovada: **o valor mudou no próprio banco depois do discovery** (mesmo arquivo, mesma linha única). O autor da mudança não é rastreável (o Firebird 2.5 não guarda histórico de valores e o SGV não tem tabela de log de parâmetros); a hipótese mais simples é a alteração do parâmetro "usar reforma tributária" no SGV 5.1.0.4, que é quem lê esse parâmetro. Por isso o Agent nunca reaproveita um estado anterior.
Consequência medida (TESTESOFICIAIS, RTC ligada de fato): 521/521 produtos com `CCLASSTRIB_MISSING` ⇒ cobertura real 0%; com RTC desligada (estado do piloto) 94,82%.
+## Determinação e preenchimento do cClassTrib
+Ver `docs/cclasstrib_resolution.md` (fontes oficiais, catálogo local × oficial, regras) e `docs/rtc_auto_apply.md` (auto-apply restrito a `CCLASSTRIB`, desligado por padrão).
+
## Testes
RTC off/on, `CCLASSTRIB` vazio/válido/inválido/órfão/expirado, catálogo inválido: `central/tests/test_unified_fiscal_coverage.py`, `agent/tests/test_unified_fiscal.py`.
diff --git a/docs/runs/ncm_valid_codes.txt b/docs/runs/ncm_valid_codes.txt
new file mode 100644
index 0000000..0a23ec4
--- /dev/null
+++ b/docs/runs/ncm_valid_codes.txt
@@ -0,0 +1,10515 @@
+01012100
+01012900
+01013000
+01019000
+01022110
+01022190
+01022911
+01022919
+01022990
+01023110
+01023190
+01023911
+01023919
+01023990
+01029000
+01031000
+01039100
+01039200
+01041011
+01041019
+01041090
+01042010
+01042090
+01051110
+01051190
+01051200
+01051300
+01051400
+01051500
+01059400
+01059900
+01061100
+01061200
+01061300
+01061400
+01061900
+01062000
+01063100
+01063200
+01063310
+01063390
+01063900
+01064100
+01064900
+01069000
+02011000
+02012010
+02012020
+02012090
+02013000
+02021000
+02022010
+02022020
+02022090
+02023000
+02031100
+02031200
+02031900
+02032100
+02032200
+02032900
+02041000
+02042100
+02042200
+02042300
+02043000
+02044100
+02044200
+02044300
+02045000
+02050000
+02061000
+02062100
+02062200
+02062910
+02062990
+02063000
+02064100
+02064900
+02068000
+02069000
+02071100
+02071210
+02071220
+02071300
+02071411
+02071412
+02071413
+02071419
+02071421
+02071422
+02071423
+02071424
+02071429
+02071431
+02071432
+02071433
+02071434
+02071439
+02072400
+02072500
+02072600
+02072700
+02074100
+02074200
+02074300
+02074400
+02074500
+02075100
+02075200
+02075300
+02075400
+02075500
+02076000
+02081000
+02083000
+02084000
+02085000
+02086000
+02089000
+02091011
+02091019
+02091021
+02091029
+02099000
+02101100
+02101200
+02101900
+02102000
+02109100
+02109200
+02109300
+02109911
+02109919
+02109920
+02109930
+02109940
+02109990
+03011110
+03011190
+03011900
+03019110
+03019190
+03019210
+03019290
+03019310
+03019390
+03019410
+03019490
+03019510
+03019590
+03019911
+03019912
+03019919
+03019991
+03019992
+03019999
+03021100
+03021300
+03021400
+03021900
+03022100
+03022200
+03022300
+03022400
+03022900
+03023100
+03023200
+03023300
+03023400
+03023500
+03023600
+03023900
+03024100
+03024210
+03024290
+03024300
+03024400
+03024500
+03024600
+03024700
+03024910
+03024990
+03025100
+03025200
+03025300
+03025400
+03025500
+03025600
+03025900
+03027100
+03027210
+03027290
+03027300
+03027400
+03027900
+03028100
+03028200
+03028310
+03028320
+03028400
+03028500
+03028910
+03028921
+03028922
+03028923
+03028924
+03028931
+03028932
+03028933
+03028934
+03028935
+03028936
+03028937
+03028938
+03028941
+03028942
+03028943
+03028944
+03028945
+03028990
+03029110
+03029190
+03029200
+03029900
+03031100
+03031200
+03031300
+03031400
+03031900
+03032300
+03032410
+03032490
+03032500
+03032600
+03032900
+03033100
+03033200
+03033300
+03033400
+03033900
+03034100
+03034200
+03034300
+03034400
+03034500
+03034600
+03034900
+03035100
+03035300
+03035400
+03035500
+03035600
+03035700
+03035910
+03035920
+03035990
+03036300
+03036400
+03036500
+03036600
+03036700
+03036800
+03036910
+03036990
+03038111
+03038112
+03038113
+03038114
+03038119
+03038190
+03038200
+03038311
+03038319
+03038321
+03038329
+03038400
+03038910
+03038920
+03038932
+03038933
+03038941
+03038942
+03038943
+03038944
+03038945
+03038946
+03038951
+03038952
+03038953
+03038954
+03038955
+03038956
+03038961
+03038962
+03038963
+03038964
+03038965
+03038990
+03039110
+03039190
+03039200
+03039910
+03039920
+03039990
+03043100
+03043210
+03043290
+03043300
+03043900
+03044100
+03044200
+03044300
+03044400
+03044500
+03044600
+03044700
+03044800
+03044910
+03044920
+03044990
+03045100
+03045200
+03045300
+03045400
+03045500
+03045600
+03045700
+03045900
+03046100
+03046210
+03046290
+03046300
+03046900
+03047100
+03047200
+03047300
+03047400
+03047500
+03047900
+03048100
+03048200
+03048300
+03048400
+03048510
+03048520
+03048600
+03048700
+03048810
+03048890
+03048910
+03048920
+03048930
+03048990
+03049100
+03049211
+03049212
+03049219
+03049221
+03049222
+03049229
+03049300
+03049400
+03049500
+03049600
+03049700
+03049900
+03052010
+03052090
+03053100
+03053210
+03053220
+03053230
+03053290
+03053900
+03054100
+03054200
+03054300
+03054400
+03054910
+03054920
+03054990
+03055100
+03055200
+03055310
+03055390
+03055400
+03055900
+03056100
+03056200
+03056300
+03056400
+03056910
+03056990
+03057100
+03057200
+03057900
+03061110
+03061190
+03061200
+03061400
+03061500
+03061610
+03061690
+03061710
+03061790
+03061910
+03061990
+03063100
+03063200
+03063300
+03063400
+03063500
+03063600
+03063910
+03063990
+03069100
+03069200
+03069300
+03069400
+03069500
+03069910
+03069990
+03071100
+03071200
+03071900
+03072100
+03072200
+03072900
+03073100
+03073200
+03073900
+03074200
+03074310
+03074320
+03074900
+03075100
+03075200
+03075900
+03076000
+03077100
+03077200
+03077900
+03078100
+03078200
+03078300
+03078400
+03078700
+03078800
+03079100
+03079200
+03079900
+03081100
+03081200
+03081900
+03082100
+03082200
+03082900
+03083000
+03089000
+03091000
+03099000
+04011010
+04011090
+04012010
+04012090
+04014010
+04014021
+04014029
+04015010
+04015021
+04015029
+04021010
+04021090
+04022110
+04022120
+04022130
+04022910
+04022920
+04022930
+04029100
+04029900
+04032000
+04039000
+04041000
+04049000
+04051000
+04052000
+04059010
+04059090
+04061010
+04061090
+04062000
+04063000
+04064000
+04069010
+04069020
+04069030
+04069090
+04071100
+04071900
+04072100
+04072900
+04079000
+04081100
+04081900
+04089100
+04089900
+04090000
+04101000
+04109000
+05010000
+05021011
+05021019
+05021090
+05029010
+05029020
+05040011
+05040012
+05040013
+05040019
+05040090
+05051000
+05059000
+05061000
+05069000
+05071000
+05079000
+05080000
+05100010
+05100090
+05111000
+05119110
+05119190
+05119910
+05119920
+05119930
+05119991
+05119999
+06011000
+06012000
+06021000
+06022000
+06023000
+06024000
+06029010
+06029021
+06029029
+06029081
+06029082
+06029083
+06029089
+06029090
+06031100
+06031200
+06031300
+06031400
+06031500
+06031900
+06039000
+06042000
+06049000
+07011000
+07019000
+07020000
+07031011
+07031019
+07031021
+07031029
+07032010
+07032090
+07039010
+07039090
+07041000
+07042000
+07049000
+07051100
+07051900
+07052100
+07052900
+07061000
+07069000
+07070000
+07081000
+07082000
+07089000
+07092000
+07093000
+07094000
+07095100
+07095200
+07095300
+07095400
+07095500
+07095600
+07095900
+07096000
+07097000
+07099100
+07099200
+07099300
+07099911
+07099919
+07099990
+07101000
+07102100
+07102200
+07102900
+07103000
+07104000
+07108000
+07109000
+07112010
+07112020
+07112090
+07114000
+07115100
+07115900
+07119000
+07122000
+07123100
+07123200
+07123300
+07123400
+07123900
+07129020
+07129090
+07131010
+07131090
+07132010
+07132090
+07133110
+07133190
+07133210
+07133290
+07133311
+07133319
+07133321
+07133329
+07133391
+07133399
+07133410
+07133490
+07133510
+07133590
+07133910
+07133990
+07134010
+07134090
+07135010
+07135090
+07136010
+07136090
+07139010
+07139090
+07141000
+07142000
+07143000
+07144000
+07145000
+07149000
+08011100
+08011200
+08011900
+08012100
+08012200
+08013100
+08013200
+08021100
+08021200
+08022100
+08022200
+08023100
+08023200
+08024100
+08024200
+08025100
+08025200
+08026100
+08026200
+08027000
+08028000
+08029100
+08029200
+08029900
+08031000
+08039000
+08041010
+08041020
+08042010
+08042020
+08043000
+08044000
+08045010
+08045020
+08045030
+08051000
+08052100
+08052200
+08052900
+08054000
+08055000
+08059000
+08061000
+08062000
+08071100
+08071900
+08072000
+08081000
+08083000
+08084000
+08091000
+08092100
+08092900
+08093010
+08093020
+08094000
+08101000
+08102000
+08103000
+08104000
+08105000
+08106000
+08107000
+08109011
+08109012
+08109013
+08109014
+08109015
+08109016
+08109017
+08109090
+08111000
+08112000
+08119000
+08121000
+08129000
+08131000
+08132010
+08132020
+08133000
+08134010
+08134090
+08135000
+08140000
+09011110
+09011190
+09011200
+09012100
+09012200
+09019000
+09021000
+09022000
+09023000
+09024000
+09030010
+09030090
+09041100
+09041200
+09042100
+09042200
+09051000
+09052000
+09061100
+09061900
+09062000
+09071000
+09072000
+09081100
+09081200
+09082100
+09082200
+09083100
+09083200
+09092100
+09092200
+09093100
+09093200
+09096110
+09096120
+09096190
+09096210
+09096220
+09096290
+09101100
+09101200
+09102000
+09103000
+09109100
+09109900
+10011100
+10011900
+10019100
+10019900
+10021000
+10029000
+10031000
+10039010
+10039080
+10039090
+10041000
+10049000
+10051000
+10059010
+10059090
+10061010
+10061091
+10061092
+10062010
+10062020
+10063011
+10063019
+10063021
+10063029
+10064000
+10071000
+10079000
+10081010
+10081090
+10082110
+10082190
+10082910
+10082990
+10083010
+10083090
+10084010
+10084090
+10085010
+10085090
+10086010
+10086090
+10089010
+10089090
+11010010
+11010020
+11022000
+11029000
+11031100
+11031300
+11031900
+11032000
+11041200
+11041900
+11042200
+11042300
+11042900
+11043000
+11051000
+11052000
+11061000
+11062000
+11063000
+11071010
+11071020
+11072010
+11072020
+11081100
+11081200
+11081300
+11081400
+11081900
+11082000
+11090000
+12011000
+12019000
+12023000
+12024100
+12024200
+12030000
+12040010
+12040090
+12051010
+12051090
+12059010
+12059090
+12060010
+12060090
+12071010
+12071090
+12072100
+12072900
+12073010
+12073090
+12074010
+12074090
+12075010
+12075090
+12076010
+12076090
+12077010
+12077090
+12079110
+12079190
+12079910
+12079990
+12081000
+12089000
+12091000
+12092100
+12092200
+12092300
+12092400
+12092500
+12092900
+12093000
+12099100
+12099900
+12101000
+12102010
+12102020
+12112000
+12113000
+12114000
+12115000
+12116000
+12119010
+12119090
+12122100
+12122900
+12129100
+12129200
+12129300
+12129400
+12129910
+12129990
+12130000
+12141000
+12149000
+13012000
+13019010
+13019090
+13021110
+13021190
+13021200
+13021300
+13021400
+13021910
+13021920
+13021930
+13021940
+13021950
+13021960
+13021991
+13021999
+13022010
+13022090
+13023100
+13023211
+13023219
+13023220
+13023910
+13023990
+14011000
+14012000
+14019000
+14042010
+14042090
+14049010
+14049090
+15011000
+15012000
+15019000
+15021011
+15021012
+15021019
+15021090
+15029000
+15030000
+15041011
+15041019
+15041090
+15042000
+15043000
+15050010
+15050090
+15060000
+15071000
+15079011
+15079019
+15079090
+15081000
+15089000
+15092000
+15093000
+15094000
+15099010
+15099090
+15101000
+15109000
+15111000
+15119000
+15121110
+15121120
+15121911
+15121919
+15121920
+15122100
+15122910
+15122990
+15131100
+15131900
+15132111
+15132119
+15132120
+15132911
+15132919
+15132920
+15141100
+15141910
+15141990
+15149100
+15149910
+15149990
+15151100
+15151900
+15152100
+15152910
+15152990
+15153000
+15155000
+15156000
+15159010
+15159021
+15159022
+15159090
+15161000
+15162000
+15163000
+15171000
+15179010
+15179090
+15180010
+15180090
+15200010
+15200020
+15211000
+15219011
+15219019
+15219090
+15220000
+16010000
+16021000
+16022000
+16023100
+16023210
+16023220
+16023230
+16023290
+16023900
+16024100
+16024200
+16024900
+16025000
+16029000
+16030000
+16041100
+16041200
+16041310
+16041390
+16041410
+16041420
+16041430
+16041500
+16041600
+16041700
+16041800
+16041900
+16042010
+16042020
+16042030
+16042090
+16043100
+16043200
+16051000
+16052100
+16052900
+16053000
+16054000
+16055100
+16055200
+16055300
+16055400
+16055500
+16055600
+16055700
+16055800
+16055900
+16056100
+16056200
+16056300
+16056900
+17011200
+17011300
+17011400
+17019100
+17019900
+17021100
+17021900
+17022000
+17023011
+17023019
+17023020
+17024010
+17024020
+17025000
+17026010
+17026020
+17029000
+17031000
+17039000
+17041000
+17049010
+17049020
+17049090
+18010000
+18020000
+18031000
+18032000
+18040000
+18050000
+18061000
+18062000
+18063110
+18063120
+18063210
+18063220
+18069000
+19011010
+19011020
+19011030
+19011090
+19012010
+19012020
+19012090
+19019010
+19019020
+19019090
+19021100
+19021900
+19022000
+19023000
+19024000
+19030000
+19041000
+19042000
+19043000
+19049000
+19051000
+19052010
+19052090
+19053100
+19053200
+19054000
+19059010
+19059020
+19059090
+20011000
+20019000
+20021000
+20029000
+20031000
+20039000
+20041000
+20049000
+20051000
+20052000
+20054000
+20055100
+20055900
+20056000
+20057000
+20058000
+20059100
+20059900
+20060000
+20071000
+20079100
+20079910
+20079921
+20079922
+20079923
+20079924
+20079925
+20079926
+20079927
+20079929
+20079990
+20081100
+20081900
+20082010
+20082090
+20083000
+20084010
+20084090
+20085000
+20086010
+20086090
+20087010
+20087020
+20087090
+20088000
+20089100
+20089300
+20089710
+20089790
+20089900
+20091100
+20091200
+20091900
+20092100
+20092900
+20093100
+20093900
+20094100
+20094900
+20095000
+20096100
+20096900
+20097100
+20097900
+20098100
+20098911
+20098912
+20098913
+20098919
+20098921
+20098922
+20098990
+20099000
+21011110
+21011190
+21011200
+21012010
+21012020
+21013000
+21021010
+21021090
+21022000
+21023000
+21031010
+21031090
+21032010
+21032090
+21033010
+21033021
+21033029
+21039011
+21039019
+21039021
+21039029
+21039091
+21039099
+21041011
+21041019
+21041021
+21041029
+21042000
+21050010
+21050090
+21061000
+21069010
+21069021
+21069029
+21069030
+21069040
+21069050
+21069060
+21069090
+22011000
+22019000
+22021000
+22029100
+22029900
+22030000
+22041010
+22041090
+22042100
+22042211
+22042219
+22042220
+22042910
+22042920
+22043000
+22051000
+22059000
+22060010
+22060090
+22071010
+22071090
+22072011
+22072019
+22072020
+22082000
+22083010
+22083020
+22083090
+22084000
+22085000
+22086000
+22087000
+22089000
+22090000
+23011010
+23011090
+23012010
+23012090
+23021000
+23023010
+23023090
+23024000
+23025000
+23031000
+23032000
+23033000
+23040010
+23040090
+23050000
+23061000
+23062000
+23063010
+23063090
+23064100
+23064900
+23065000
+23066000
+23069010
+23069090
+23070000
+23080000
+23091000
+23099010
+23099020
+23099030
+23099040
+23099050
+23099060
+23099070
+23099090
+24011010
+24011020
+24011030
+24011040
+24011090
+24012010
+24012020
+24012030
+24012040
+24012090
+24013000
+24021000
+24022000
+24029000
+24031100
+24031900
+24039100
+24039910
+24039990
+24041100
+24041200
+24041900
+24049100
+24049200
+24049900
+25010011
+25010019
+25010020
+25010090
+25020000
+25030010
+25030090
+25041000
+25049000
+25051000
+25059000
+25061000
+25062000
+25070010
+25070090
+25081000
+25083000
+25084010
+25084090
+25085000
+25086000
+25087000
+25090000
+25101010
+25101090
+25102010
+25102090
+25111000
+25112000
+25120000
+25131000
+25132000
+25140000
+25151100
+25151210
+25151220
+25152000
+25161100
+25161200
+25162000
+25169000
+25171000
+25172000
+25173000
+25174100
+25174900
+25181000
+25182000
+25191000
+25199010
+25199090
+25201011
+25201019
+25201020
+25202010
+25202090
+25210000
+25221000
+25222000
+25223000
+25231000
+25232100
+25232910
+25232990
+25233000
+25239000
+25241000
+25249000
+25251000
+25252000
+25253000
+25261000
+25262000
+25280000
+25291000
+25292100
+25292200
+25293000
+25301010
+25301090
+25302000
+25309010
+25309020
+25309030
+25309040
+25309090
+26011100
+26011210
+26011220
+26011290
+26012000
+26020010
+26020090
+26030010
+26030090
+26040000
+26050000
+26060011
+26060012
+26060090
+26070000
+26080010
+26080090
+26090000
+26100010
+26100090
+26110000
+26121000
+26122000
+26131010
+26131090
+26139010
+26139090
+26140010
+26140090
+26151010
+26151020
+26151090
+26159000
+26161000
+26169000
+26171000
+26179000
+26180000
+26190000
+26201100
+26201900
+26202100
+26202900
+26203000
+26204000
+26206000
+26209100
+26209910
+26209990
+26211000
+26219010
+26219090
+27011100
+27011200
+27011900
+27012000
+27021000
+27022000
+27030000
+27040011
+27040012
+27040090
+27050000
+27060000
+27071000
+27072000
+27073000
+27074000
+27075010
+27075090
+27079100
+27079910
+27079990
+27081000
+27082000
+27090010
+27090090
+27101210
+27101221
+27101229
+27101230
+27101241
+27101249
+27101251
+27101259
+27101260
+27101290
+27101911
+27101919
+27101921
+27101922
+27101929
+27101931
+27101932
+27101991
+27101992
+27101993
+27101994
+27101999
+27102000
+27109110
+27109120
+27109190
+27109900
+27111100
+27111210
+27111290
+27111300
+27111400
+27111910
+27111990
+27112100
+27112910
+27112990
+27121000
+27122000
+27129000
+27131100
+27131200
+27132000
+27139000
+27141000
+27149000
+27150000
+27160000
+28011000
+28012010
+28012090
+28013000
+28020000
+28030011
+28030019
+28030090
+28041000
+28042100
+28042910
+28042990
+28043000
+28044000
+28045000
+28046100
+28046900
+28047010
+28047020
+28047030
+28048000
+28049000
+28051100
+28051200
+28051910
+28051920
+28051990
+28053010
+28053090
+28054000
+28061010
+28061020
+28062000
+28070010
+28070020
+28080010
+28080020
+28091000
+28092011
+28092019
+28092020
+28092030
+28092090
+28100010
+28100090
+28111100
+28111200
+28111910
+28111920
+28111930
+28111940
+28111990
+28112100
+28112210
+28112220
+28112230
+28112290
+28112910
+28112990
+28121100
+28121200
+28121300
+28121400
+28121500
+28121600
+28121700
+28121911
+28121919
+28121920
+28129000
+28131000
+28139010
+28139090
+28141000
+28142000
+28151100
+28151200
+28152000
+28153000
+28161010
+28161020
+28164010
+28164090
+28170010
+28170020
+28181010
+28181090
+28182010
+28182090
+28183000
+28191000
+28199010
+28199020
+28201010
+28201090
+28209010
+28209020
+28209030
+28209040
+28211011
+28211019
+28211020
+28211030
+28211090
+28212000
+28220010
+28220090
+28230010
+28230090
+28241000
+28249010
+28249090
+28251010
+28251020
+28252010
+28252020
+28253010
+28253090
+28254010
+28254090
+28255010
+28255090
+28256010
+28256020
+28257010
+28257090
+28258010
+28258090
+28259010
+28259020
+28259090
+28261200
+28261910
+28261920
+28261990
+28263000
+28269010
+28269020
+28269090
+28271000
+28272010
+28272090
+28273110
+28273190
+28273200
+28273500
+28273910
+28273920
+28273931
+28273939
+28273940
+28273950
+28273960
+28273970
+28273991
+28273992
+28273993
+28273994
+28273995
+28273996
+28273997
+28273999
+28274110
+28274120
+28274911
+28274912
+28274919
+28274921
+28274929
+28275100
+28275900
+28276011
+28276012
+28276019
+28276021
+28276029
+28281000
+28289011
+28289019
+28289020
+28289090
+28291100
+28291910
+28291920
+28291990
+28299011
+28299012
+28299019
+28299021
+28299022
+28299029
+28299031
+28299032
+28299039
+28299040
+28299050
+28301010
+28301020
+28309011
+28309012
+28309013
+28309014
+28309015
+28309016
+28309019
+28309020
+28311011
+28311019
+28311021
+28311029
+28319010
+28319090
+28321010
+28321090
+28322000
+28323010
+28323020
+28323090
+28331110
+28331190
+28331900
+28332100
+28332200
+28332400
+28332510
+28332520
+28332710
+28332790
+28332910
+28332920
+28332930
+28332940
+28332950
+28332960
+28332970
+28332990
+28333000
+28334010
+28334020
+28334090
+28341010
+28341090
+28342110
+28342190
+28342910
+28342930
+28342940
+28342990
+28351011
+28351019
+28351021
+28351029
+28352200
+28352400
+28352500
+28352600
+28352910
+28352920
+28352930
+28352940
+28352950
+28352960
+28352970
+28352980
+28352990
+28353110
+28353190
+28353910
+28353920
+28353930
+28353990
+28362010
+28362090
+28363000
+28364000
+28365000
+28366010
+28366090
+28369100
+28369200
+28369911
+28369912
+28369913
+28369919
+28369920
+28371100
+28371911
+28371912
+28371914
+28371915
+28371919
+28371920
+28372011
+28372012
+28372019
+28372021
+28372022
+28372023
+28372029
+28372090
+28391100
+28391900
+28399010
+28399020
+28399030
+28399040
+28399050
+28399090
+28401100
+28401900
+28402000
+28403000
+28413000
+28415011
+28415012
+28415013
+28415014
+28415015
+28415016
+28415019
+28415020
+28416100
+28416910
+28416920
+28416930
+28417010
+28417020
+28417090
+28418010
+28418020
+28418090
+28419011
+28419012
+28419013
+28419014
+28419015
+28419019
+28419021
+28419022
+28419029
+28419030
+28419041
+28419042
+28419043
+28419049
+28419050
+28419060
+28419070
+28419081
+28419082
+28419083
+28419089
+28419090
+28421010
+28421090
+28429000
+28431000
+28432100
+28432910
+28432990
+28433010
+28433090
+28439011
+28439019
+28439020
+28439030
+28439040
+28439090
+28441000
+28442000
+28443000
+28444100
+28444200
+28444310
+28444320
+28444330
+28444390
+28444400
+28445000
+28451000
+28452000
+28453000
+28454000
+28459000
+28461010
+28461090
+28469010
+28469020
+28469030
+28469090
+28470000
+28491000
+28492000
+28499010
+28499020
+28499030
+28499090
+28500010
+28500020
+28500090
+28521011
+28521012
+28521013
+28521014
+28521019
+28521021
+28521022
+28521023
+28521024
+28521025
+28521029
+28529000
+28531000
+28539011
+28539012
+28539013
+28539019
+28539020
+28539030
+28539090
+29011000
+29012100
+29012200
+29012300
+29012410
+29012420
+29012900
+29021100
+29021910
+29021990
+29022000
+29023000
+29024100
+29024200
+29024300
+29024400
+29025000
+29026000
+29027000
+29029010
+29029020
+29029030
+29029040
+29029090
+29031110
+29031120
+29031200
+29031300
+29031400
+29031500
+29031910
+29031920
+29031990
+29032100
+29032200
+29032300
+29032910
+29032990
+29034100
+29034200
+29034300
+29034400
+29034510
+29034520
+29034600
+29034700
+29034800
+29034900
+29035100
+29035910
+29035990
+29036100
+29036200
+29036910
+29036920
+29036990
+29037100
+29037200
+29037300
+29037400
+29037500
+29037600
+29037711
+29037712
+29037713
+29037721
+29037722
+29037723
+29037724
+29037731
+29037732
+29037733
+29037734
+29037735
+29037736
+29037737
+29037790
+29037800
+29037911
+29037912
+29037919
+29037920
+29037931
+29037939
+29037990
+29038110
+29038120
+29038130
+29038190
+29038210
+29038220
+29038230
+29038300
+29038910
+29038990
+29039110
+29039120
+29039130
+29039210
+29039220
+29039300
+29039400
+29039911
+29039912
+29039913
+29039914
+29039915
+29039916
+29039917
+29039918
+29039919
+29039921
+29039922
+29039923
+29039924
+29039929
+29039931
+29039939
+29039990
+29041011
+29041012
+29041013
+29041019
+29041020
+29041030
+29041040
+29041051
+29041052
+29041053
+29041059
+29041060
+29041090
+29042010
+29042020
+29042030
+29042041
+29042049
+29042051
+29042052
+29042059
+29042060
+29042070
+29042090
+29043100
+29043200
+29043300
+29043400
+29043500
+29043600
+29049100
+29049911
+29049912
+29049913
+29049914
+29049915
+29049916
+29049919
+29049921
+29049929
+29049930
+29049940
+29049990
+29051100
+29051210
+29051220
+29051300
+29051410
+29051420
+29051430
+29051600
+29051710
+29051720
+29051730
+29051911
+29051912
+29051919
+29051921
+29051922
+29051923
+29051929
+29051991
+29051992
+29051993
+29051994
+29051995
+29051996
+29051999
+29052210
+29052220
+29052230
+29052290
+29052910
+29052990
+29053100
+29053200
+29053910
+29053920
+29053930
+29053990
+29054100
+29054200
+29054300
+29054400
+29054500
+29054900
+29055100
+29055910
+29055990
+29061100
+29061200
+29061300
+29061910
+29061920
+29061930
+29061940
+29061950
+29061990
+29062100
+29062910
+29062920
+29062990
+29071100
+29071200
+29071300
+29071510
+29071590
+29071910
+29071920
+29071930
+29071940
+29071990
+29072100
+29072200
+29072300
+29072900
+29081100
+29081911
+29081912
+29081913
+29081914
+29081915
+29081916
+29081919
+29081921
+29081929
+29081990
+29089100
+29089200
+29089912
+29089913
+29089919
+29089921
+29089929
+29089930
+29089990
+29091100
+29091910
+29091920
+29091990
+29092000
+29093011
+29093012
+29093013
+29093014
+29093019
+29093021
+29093022
+29093023
+29093024
+29093025
+29093029
+29094100
+29094310
+29094320
+29094411
+29094412
+29094413
+29094419
+29094421
+29094429
+29094910
+29094921
+29094922
+29094923
+29094924
+29094929
+29094931
+29094932
+29094939
+29094941
+29094949
+29094950
+29094990
+29095011
+29095012
+29095013
+29095019
+29095090
+29096011
+29096012
+29096013
+29096019
+29096090
+29101000
+29102000
+29103000
+29104000
+29105000
+29109010
+29109090
+29110010
+29110090
+29121100
+29121200
+29121911
+29121912
+29121919
+29121921
+29121922
+29121923
+29121929
+29121991
+29121999
+29122100
+29122910
+29122920
+29122990
+29124100
+29124200
+29124910
+29124920
+29124930
+29124941
+29124949
+29124990
+29125000
+29126000
+29130010
+29130090
+29141100
+29141200
+29141300
+29141910
+29141921
+29141922
+29141923
+29141929
+29141930
+29141940
+29141950
+29141990
+29142210
+29142220
+29142310
+29142320
+29142910
+29142920
+29142990
+29143100
+29143910
+29143990
+29144010
+29144091
+29144099
+29145010
+29145020
+29145090
+29146100
+29146200
+29146910
+29146920
+29146990
+29147100
+29147911
+29147919
+29147921
+29147922
+29147929
+29147990
+29151100
+29151210
+29151290
+29151310
+29151390
+29152100
+29152400
+29152910
+29152920
+29152990
+29153100
+29153200
+29153300
+29153600
+29153910
+29153921
+29153929
+29153931
+29153932
+29153939
+29153941
+29153942
+29153951
+29153952
+29153953
+29153954
+29153955
+29153961
+29153962
+29153963
+29153991
+29153992
+29153993
+29153994
+29153999
+29154010
+29154020
+29154090
+29155010
+29155020
+29155030
+29156011
+29156012
+29156019
+29156021
+29156029
+29157011
+29157019
+29157020
+29157031
+29157039
+29157040
+29159010
+29159021
+29159022
+29159023
+29159024
+29159029
+29159031
+29159032
+29159033
+29159039
+29159041
+29159043
+29159049
+29159050
+29159060
+29159070
+29159090
+29161110
+29161120
+29161210
+29161220
+29161230
+29161240
+29161290
+29161310
+29161320
+29161410
+29161420
+29161430
+29161490
+29161511
+29161519
+29161520
+29161600
+29161911
+29161919
+29161921
+29161922
+29161923
+29161929
+29161990
+29162011
+29162012
+29162013
+29162014
+29162015
+29162019
+29162090
+29163110
+29163121
+29163122
+29163129
+29163131
+29163132
+29163139
+29163210
+29163220
+29163400
+29163910
+29163920
+29163930
+29163940
+29163990
+29171110
+29171120
+29171210
+29171220
+29171310
+29171321
+29171322
+29171323
+29171329
+29171400
+29171910
+29171921
+29171922
+29171930
+29171990
+29172000
+29173200
+29173300
+29173400
+29173500
+29173600
+29173700
+29173911
+29173919
+29173920
+29173931
+29173939
+29173940
+29173950
+29173990
+29181100
+29181200
+29181310
+29181320
+29181400
+29181500
+29181610
+29181690
+29181700
+29181800
+29181910
+29181921
+29181922
+29181929
+29181930
+29181942
+29181943
+29181990
+29182110
+29182120
+29182211
+29182212
+29182219
+29182220
+29182300
+29182910
+29182921
+29182922
+29182923
+29182929
+29182930
+29182940
+29182950
+29182990
+29183010
+29183020
+29183031
+29183032
+29183033
+29183039
+29183040
+29183090
+29189100
+29189911
+29189912
+29189919
+29189921
+29189929
+29189930
+29189940
+29189950
+29189960
+29189991
+29189992
+29189993
+29189994
+29189999
+29191000
+29199010
+29199020
+29199030
+29199040
+29199050
+29199060
+29199090
+29201110
+29201120
+29201910
+29201920
+29201990
+29202100
+29202200
+29202300
+29202400
+29202910
+29202920
+29202930
+29202940
+29202950
+29202990
+29203000
+29209022
+29209029
+29209031
+29209032
+29209033
+29209039
+29209041
+29209042
+29209049
+29209051
+29209059
+29209090
+29211111
+29211112
+29211121
+29211122
+29211123
+29211129
+29211131
+29211132
+29211139
+29211200
+29211300
+29211400
+29211911
+29211912
+29211913
+29211914
+29211915
+29211919
+29211921
+29211922
+29211923
+29211924
+29211929
+29211931
+29211939
+29211941
+29211949
+29211991
+29211992
+29211993
+29211994
+29211999
+29212100
+29212200
+29212910
+29212920
+29212990
+29213011
+29213012
+29213019
+29213020
+29213090
+29214100
+29214211
+29214219
+29214221
+29214229
+29214231
+29214239
+29214241
+29214249
+29214290
+29214311
+29214319
+29214321
+29214322
+29214323
+29214329
+29214410
+29214421
+29214422
+29214429
+29214500
+29214610
+29214620
+29214630
+29214640
+29214650
+29214660
+29214670
+29214680
+29214690
+29214910
+29214921
+29214922
+29214929
+29214931
+29214939
+29214990
+29215111
+29215112
+29215119
+29215120
+29215131
+29215132
+29215133
+29215134
+29215135
+29215139
+29215190
+29215911
+29215919
+29215921
+29215929
+29215931
+29215932
+29215939
+29215990
+29221100
+29221200
+29221400
+29221500
+29221600
+29221700
+29221800
+29221911
+29221912
+29221913
+29221919
+29221921
+29221929
+29221931
+29221939
+29221941
+29221949
+29221951
+29221952
+29221959
+29221971
+29221979
+29221981
+29221989
+29221991
+29221992
+29221993
+29221994
+29221995
+29221996
+29221999
+29222100
+29222911
+29222919
+29222920
+29222990
+29223111
+29223112
+29223120
+29223130
+29223910
+29223921
+29223929
+29223990
+29224110
+29224190
+29224210
+29224220
+29224300
+29224410
+29224420
+29224910
+29224920
+29224931
+29224932
+29224940
+29224951
+29224952
+29224959
+29224961
+29224962
+29224963
+29224964
+29224969
+29224990
+29225011
+29225019
+29225031
+29225032
+29225039
+29225091
+29225099
+29231000
+29232000
+29233000
+29234000
+29239010
+29239020
+29239030
+29239040
+29239050
+29239060
+29239090
+29241100
+29241210
+29241220
+29241230
+29241911
+29241919
+29241921
+29241922
+29241929
+29241931
+29241932
+29241939
+29241942
+29241949
+29241991
+29241992
+29241993
+29241994
+29241999
+29242111
+29242119
+29242120
+29242190
+29242300
+29242400
+29242500
+29242911
+29242912
+29242913
+29242914
+29242915
+29242919
+29242920
+29242931
+29242932
+29242939
+29242941
+29242943
+29242944
+29242945
+29242946
+29242947
+29242949
+29242951
+29242952
+29242959
+29242961
+29242962
+29242963
+29242964
+29242969
+29242991
+29242992
+29242993
+29242994
+29242995
+29242996
+29242999
+29251100
+29251200
+29251910
+29251990
+29252100
+29252911
+29252919
+29252921
+29252922
+29252923
+29252929
+29252930
+29252940
+29252950
+29252990
+29261000
+29262000
+29263011
+29263012
+29263020
+29264000
+29269011
+29269012
+29269019
+29269021
+29269022
+29269023
+29269024
+29269025
+29269026
+29269029
+29269030
+29269091
+29269092
+29269093
+29269095
+29269096
+29269099
+29270010
+29270021
+29270029
+29270030
+29280011
+29280019
+29280020
+29280030
+29280041
+29280042
+29280090
+29291010
+29291021
+29291029
+29291030
+29291090
+29299011
+29299012
+29299019
+29299031
+29299039
+29299040
+29299050
+29299060
+29299090
+29301000
+29302011
+29302012
+29302013
+29302019
+29302021
+29302022
+29302023
+29302024
+29302029
+29303011
+29303012
+29303019
+29303021
+29303022
+29303029
+29303090
+29304010
+29304090
+29306000
+29307000
+29308010
+29308020
+29308030
+29309011
+29309012
+29309013
+29309019
+29309021
+29309022
+29309023
+29309029
+29309031
+29309032
+29309033
+29309034
+29309035
+29309036
+29309037
+29309039
+29309041
+29309042
+29309043
+29309049
+29309051
+29309052
+29309053
+29309054
+29309057
+29309059
+29309061
+29309069
+29309071
+29309072
+29309079
+29309081
+29309082
+29309083
+29309084
+29309085
+29309086
+29309087
+29309088
+29309089
+29309091
+29309093
+29309094
+29309095
+29309096
+29309097
+29309098
+29309099
+29311000
+29312000
+29314100
+29314200
+29314300
+29314400
+29314500
+29314600
+29314700
+29314800
+29314911
+29314912
+29314913
+29314914
+29314915
+29314916
+29314920
+29314931
+29314932
+29314939
+29314940
+29314990
+29315100
+29315200
+29315300
+29315400
+29315911
+29315912
+29315913
+29315991
+29315992
+29315993
+29315994
+29315995
+29315996
+29315998
+29315999
+29319021
+29319029
+29319041
+29319042
+29319043
+29319044
+29319045
+29319046
+29319049
+29319051
+29319052
+29319053
+29319054
+29319059
+29319061
+29319062
+29319069
+29319090
+29321100
+29321200
+29321310
+29321320
+29321400
+29321910
+29321920
+29321930
+29321940
+29321950
+29321990
+29322000
+29329100
+29329200
+29329300
+29329400
+29329500
+29329600
+29329911
+29329912
+29329913
+29329991
+29329992
+29329993
+29329994
+29329999
+29331111
+29331112
+29331119
+29331120
+29331190
+29331911
+29331919
+29331990
+29332110
+29332121
+29332129
+29332190
+29332911
+29332912
+29332913
+29332919
+29332921
+29332922
+29332923
+29332924
+29332925
+29332929
+29332930
+29332940
+29332991
+29332992
+29332993
+29332994
+29332995
+29332999
+29333110
+29333120
+29333200
+29333311
+29333312
+29333319
+29333321
+29333322
+29333329
+29333331
+29333332
+29333339
+29333341
+29333342
+29333349
+29333351
+29333352
+29333359
+29333361
+29333362
+29333363
+29333369
+29333371
+29333372
+29333379
+29333381
+29333382
+29333383
+29333384
+29333389
+29333391
+29333392
+29333393
+29333394
+29333399
+29333400
+29333500
+29333600
+29333700
+29333912
+29333913
+29333914
+29333915
+29333919
+29333921
+29333922
+29333923
+29333924
+29333925
+29333929
+29333931
+29333932
+29333933
+29333934
+29333935
+29333936
+29333937
+29333939
+29333941
+29333942
+29333943
+29333944
+29333945
+29333946
+29333948
+29333949
+29333981
+29333982
+29333983
+29333984
+29333989
+29333991
+29333992
+29333993
+29333994
+29333999
+29334110
+29334120
+29334911
+29334912
+29334913
+29334919
+29334920
+29334930
+29334940
+29334990
+29335200
+29335311
+29335312
+29335321
+29335322
+29335323
+29335330
+29335340
+29335350
+29335360
+29335371
+29335372
+29335380
+29335400
+29335510
+29335520
+29335530
+29335540
+29335911
+29335912
+29335913
+29335914
+29335915
+29335916
+29335919
+29335921
+29335922
+29335923
+29335929
+29335931
+29335932
+29335933
+29335934
+29335935
+29335939
+29335941
+29335942
+29335943
+29335944
+29335945
+29335949
+29335991
+29335992
+29335999
+29336100
+29336911
+29336912
+29336913
+29336914
+29336915
+29336916
+29336919
+29336921
+29336922
+29336923
+29336929
+29336991
+29336992
+29336999
+29337100
+29337210
+29337220
+29337910
+29337990
+29339111
+29339112
+29339113
+29339114
+29339115
+29339119
+29339121
+29339122
+29339123
+29339129
+29339131
+29339132
+29339133
+29339134
+29339139
+29339141
+29339142
+29339143
+29339149
+29339151
+29339152
+29339153
+29339159
+29339161
+29339162
+29339163
+29339164
+29339169
+29339171
+29339172
+29339173
+29339179
+29339181
+29339182
+29339183
+29339189
+29339200
+29339911
+29339912
+29339913
+29339919
+29339920
+29339931
+29339932
+29339933
+29339934
+29339935
+29339939
+29339941
+29339942
+29339943
+29339944
+29339945
+29339946
+29339947
+29339949
+29339951
+29339952
+29339953
+29339954
+29339955
+29339956
+29339959
+29339961
+29339962
+29339963
+29339969
+29339991
+29339992
+29339993
+29339995
+29339996
+29339999
+29341010
+29341020
+29341030
+29341090
+29342010
+29342020
+29342031
+29342032
+29342033
+29342034
+29342039
+29342040
+29342090
+29343010
+29343020
+29343030
+29343090
+29349111
+29349112
+29349121
+29349122
+29349123
+29349129
+29349131
+29349132
+29349133
+29349141
+29349142
+29349149
+29349150
+29349160
+29349170
+29349200
+29349911
+29349912
+29349913
+29349914
+29349915
+29349919
+29349922
+29349923
+29349924
+29349925
+29349926
+29349927
+29349929
+29349931
+29349932
+29349933
+29349934
+29349935
+29349939
+29349941
+29349942
+29349943
+29349944
+29349945
+29349946
+29349949
+29349951
+29349952
+29349953
+29349954
+29349959
+29349961
+29349969
+29349991
+29349992
+29349993
+29349999
+29351000
+29352000
+29353000
+29354000
+29355000
+29359011
+29359012
+29359013
+29359014
+29359015
+29359019
+29359021
+29359022
+29359023
+29359024
+29359025
+29359029
+29359091
+29359092
+29359093
+29359094
+29359095
+29359096
+29359099
+29362111
+29362112
+29362113
+29362119
+29362190
+29362210
+29362220
+29362290
+29362310
+29362320
+29362390
+29362410
+29362490
+29362510
+29362520
+29362590
+29362610
+29362620
+29362630
+29362690
+29362710
+29362720
+29362790
+29362811
+29362812
+29362819
+29362890
+29362911
+29362919
+29362921
+29362929
+29362931
+29362939
+29362940
+29362951
+29362952
+29362953
+29362959
+29362990
+29369000
+29371100
+29371200
+29371910
+29371920
+29371930
+29371940
+29371950
+29371990
+29372110
+29372120
+29372130
+29372140
+29372210
+29372221
+29372229
+29372231
+29372239
+29372290
+29372310
+29372321
+29372322
+29372329
+29372331
+29372339
+29372341
+29372342
+29372349
+29372351
+29372359
+29372360
+29372370
+29372391
+29372392
+29372399
+29372910
+29372920
+29372931
+29372939
+29372940
+29372950
+29372960
+29372990
+29375000
+29379010
+29379030
+29379040
+29379090
+29381000
+29389010
+29389020
+29389090
+29391110
+29391121
+29391122
+29391123
+29391131
+29391132
+29391140
+29391151
+29391152
+29391153
+29391161
+29391162
+29391169
+29391170
+29391181
+29391182
+29391191
+29391192
+29391900
+29392000
+29393010
+29393020
+29394100
+29394200
+29394300
+29394400
+29394510
+29394520
+29394530
+29394900
+29395100
+29395910
+29395920
+29395990
+29396100
+29396200
+29396300
+29396911
+29396919
+29396921
+29396929
+29396931
+29396939
+29396941
+29396942
+29396949
+29396951
+29396952
+29396959
+29396990
+29397210
+29397220
+29397290
+29397911
+29397919
+29397920
+29397931
+29397939
+29397940
+29397990
+29398010
+29398090
+29400011
+29400012
+29400013
+29400019
+29400021
+29400022
+29400023
+29400029
+29400092
+29400093
+29400094
+29400099
+29411010
+29411020
+29411031
+29411039
+29411041
+29411042
+29411043
+29411049
+29411090
+29412010
+29412090
+29413010
+29413020
+29413031
+29413032
+29413090
+29414011
+29414019
+29414020
+29414090
+29415010
+29415020
+29415090
+29419011
+29419012
+29419013
+29419019
+29419021
+29419022
+29419029
+29419031
+29419032
+29419033
+29419034
+29419035
+29419036
+29419037
+29419039
+29419041
+29419042
+29419043
+29419049
+29419051
+29419059
+29419061
+29419062
+29419069
+29419071
+29419072
+29419073
+29419079
+29419081
+29419082
+29419083
+29419089
+29419091
+29419092
+29419099
+29420000
+30012010
+30012090
+30019010
+30019020
+30019031
+30019039
+30019090
+30021211
+30021212
+30021213
+30021214
+30021215
+30021216
+30021219
+30021221
+30021222
+30021223
+30021224
+30021229
+30021231
+30021232
+30021233
+30021234
+30021235
+30021236
+30021239
+30021300
+30021400
+30021510
+30021520
+30021590
+30024111
+30024112
+30024113
+30024114
+30024115
+30024116
+30024117
+30024118
+30024119
+30024121
+30024122
+30024123
+30024124
+30024125
+30024126
+30024127
+30024128
+30024129
+30024210
+30024220
+30024230
+30024240
+30024250
+30024260
+30024270
+30024280
+30024290
+30024910
+30024920
+30024991
+30024992
+30024994
+30024999
+30025100
+30025900
+30029000
+30031011
+30031012
+30031013
+30031014
+30031015
+30031019
+30031020
+30032011
+30032019
+30032021
+30032029
+30032031
+30032032
+30032039
+30032041
+30032049
+30032051
+30032052
+30032059
+30032061
+30032062
+30032063
+30032069
+30032071
+30032072
+30032073
+30032079
+30032091
+30032092
+30032093
+30032094
+30032095
+30032099
+30033100
+30033911
+30033912
+30033913
+30033914
+30033915
+30033916
+30033917
+30033918
+30033919
+30033921
+30033922
+30033923
+30033924
+30033925
+30033926
+30033927
+30033929
+30033931
+30033932
+30033933
+30033934
+30033935
+30033936
+30033937
+30033939
+30033981
+30033982
+30033991
+30033992
+30033994
+30033995
+30033999
+30034100
+30034200
+30034300
+30034910
+30034920
+30034930
+30034940
+30034950
+30034990
+30036000
+30039011
+30039012
+30039013
+30039014
+30039015
+30039016
+30039017
+30039019
+30039021
+30039022
+30039023
+30039024
+30039025
+30039029
+30039031
+30039032
+30039033
+30039034
+30039035
+30039036
+30039037
+30039038
+30039039
+30039041
+30039042
+30039043
+30039044
+30039045
+30039046
+30039047
+30039048
+30039049
+30039051
+30039052
+30039053
+30039054
+30039055
+30039056
+30039057
+30039058
+30039059
+30039061
+30039062
+30039063
+30039064
+30039065
+30039066
+30039067
+30039069
+30039071
+30039072
+30039073
+30039074
+30039075
+30039076
+30039077
+30039078
+30039079
+30039081
+30039082
+30039083
+30039084
+30039085
+30039086
+30039087
+30039088
+30039089
+30039091
+30039092
+30039093
+30039094
+30039095
+30039096
+30039097
+30039099
+30041011
+30041012
+30041013
+30041014
+30041015
+30041019
+30041020
+30042011
+30042019
+30042021
+30042029
+30042031
+30042032
+30042039
+30042041
+30042049
+30042051
+30042052
+30042059
+30042061
+30042062
+30042063
+30042069
+30042071
+30042072
+30042073
+30042079
+30042091
+30042092
+30042093
+30042094
+30042095
+30042099
+30043100
+30043210
+30043220
+30043290
+30043911
+30043912
+30043913
+30043914
+30043915
+30043916
+30043917
+30043918
+30043919
+30043921
+30043922
+30043923
+30043924
+30043925
+30043926
+30043927
+30043928
+30043929
+30043931
+30043932
+30043933
+30043934
+30043935
+30043936
+30043937
+30043939
+30043981
+30043982
+30043991
+30043992
+30043994
+30043999
+30044100
+30044200
+30044300
+30044910
+30044920
+30044930
+30044940
+30044950
+30044990
+30045010
+30045020
+30045030
+30045040
+30045050
+30045060
+30045090
+30046000
+30049011
+30049012
+30049013
+30049014
+30049015
+30049019
+30049021
+30049022
+30049023
+30049024
+30049025
+30049026
+30049027
+30049028
+30049029
+30049031
+30049032
+30049033
+30049034
+30049035
+30049036
+30049037
+30049038
+30049039
+30049041
+30049042
+30049043
+30049044
+30049045
+30049046
+30049047
+30049048
+30049049
+30049051
+30049052
+30049053
+30049054
+30049055
+30049057
+30049058
+30049059
+30049061
+30049062
+30049063
+30049064
+30049065
+30049066
+30049067
+30049068
+30049069
+30049071
+30049072
+30049073
+30049074
+30049075
+30049076
+30049077
+30049078
+30049079
+30049091
+30049092
+30049093
+30049094
+30049095
+30049096
+30049097
+30049098
+30049099
+30051010
+30051020
+30051030
+30051040
+30051050
+30051090
+30059011
+30059012
+30059019
+30059020
+30059090
+30061010
+30061020
+30061090
+30063011
+30063012
+30063013
+30063015
+30063016
+30063017
+30063018
+30063019
+30063021
+30063029
+30064011
+30064012
+30064020
+30065000
+30066000
+30067000
+30069110
+30069190
+30069200
+30069300
+31010000
+31021010
+31021090
+31022100
+31022910
+31022990
+31023000
+31024000
+31025011
+31025019
+31025090
+31026000
+31028000
+31029000
+31031100
+31031900
+31039011
+31039019
+31039090
+31042010
+31042090
+31043010
+31043090
+31049010
+31049090
+31051000
+31052000
+31053000
+31054000
+31055100
+31055900
+31056000
+31059011
+31059019
+31059090
+32011000
+32012000
+32019011
+32019012
+32019019
+32019020
+32019090
+32021000
+32029011
+32029012
+32029013
+32029019
+32029021
+32029029
+32029030
+32030011
+32030012
+32030013
+32030019
+32030021
+32030029
+32030030
+32041100
+32041210
+32041220
+32041300
+32041400
+32041510
+32041520
+32041530
+32041590
+32041600
+32041700
+32041810
+32041820
+32041830
+32041890
+32041920
+32041930
+32041990
+32042011
+32042019
+32042090
+32049000
+32050000
+32061110
+32061120
+32061130
+32061910
+32061990
+32062000
+32064100
+32064210
+32064290
+32064910
+32064920
+32064990
+32065011
+32065019
+32065021
+32065029
+32071020
+32071030
+32071090
+32072010
+32072091
+32072099
+32073000
+32074010
+32074090
+32081010
+32081020
+32081030
+32082011
+32082019
+32082020
+32082030
+32089010
+32089021
+32089029
+32089031
+32089039
+32091010
+32091020
+32099011
+32099019
+32099020
+32100010
+32100020
+32100030
+32110000
+32121000
+32129010
+32129090
+32131000
+32139000
+32141010
+32141020
+32149000
+32151100
+32151900
+32159000
+33011210
+33011290
+33011300
+33011910
+33011990
+33012400
+33012510
+33012520
+33012590
+33012911
+33012912
+33012913
+33012914
+33012915
+33012916
+33012917
+33012918
+33012919
+33012921
+33012922
+33012990
+33013000
+33019010
+33019020
+33019030
+33019040
+33021000
+33029011
+33029019
+33029091
+33029099
+33030010
+33030020
+33041000
+33042010
+33042090
+33043000
+33049100
+33049910
+33049990
+33051000
+33052000
+33053000
+33059000
+33061000
+33062000
+33069000
+33071000
+33072010
+33072090
+33073000
+33074100
+33074900
+33079000
+34011110
+34011190
+34011900
+34012010
+34012090
+34013000
+34023100
+34023910
+34023920
+34023930
+34023990
+34024110
+34024190
+34024200
+34024900
+34025000
+34029011
+34029019
+34029021
+34029022
+34029023
+34029029
+34029031
+34029039
+34029090
+34031110
+34031120
+34031190
+34031900
+34039110
+34039120
+34039190
+34039900
+34042010
+34042020
+34049011
+34049012
+34049013
+34049014
+34049019
+34049021
+34049022
+34049029
+34051000
+34052000
+34053000
+34054000
+34059000
+34060000
+34070010
+34070020
+34070090
+35011000
+35019011
+35019019
+35019020
+35021100
+35021900
+35022000
+35029010
+35029090
+35030011
+35030012
+35030019
+35030090
+35040011
+35040019
+35040020
+35040030
+35040090
+35051000
+35052000
+35061010
+35061090
+35069110
+35069120
+35069190
+35069900
+35071000
+35079011
+35079019
+35079021
+35079022
+35079023
+35079024
+35079025
+35079026
+35079029
+35079031
+35079032
+35079039
+35079041
+35079042
+35079049
+36010000
+36020000
+36031000
+36032000
+36033000
+36034000
+36035000
+36036000
+36041000
+36049010
+36049090
+36050000
+36061000
+36069000
+37011010
+37011021
+37011029
+37012010
+37012020
+37013010
+37013021
+37013022
+37013029
+37013031
+37013039
+37013040
+37013050
+37013090
+37019100
+37019900
+37021010
+37021020
+37023100
+37023200
+37023900
+37024100
+37024210
+37024290
+37024310
+37024320
+37024390
+37024410
+37024421
+37024422
+37024429
+37025200
+37025300
+37025411
+37025412
+37025419
+37025491
+37025499
+37025510
+37025590
+37025600
+37029600
+37029700
+37029800
+37031010
+37031021
+37031029
+37032000
+37039010
+37039090
+37040000
+37050010
+37050090
+37061000
+37069000
+37071000
+37079010
+37079021
+37079029
+37079030
+37079090
+38011000
+38012010
+38012090
+38013010
+38013090
+38019000
+38021000
+38029010
+38029020
+38029030
+38029040
+38029050
+38029090
+38030010
+38030090
+38040011
+38040012
+38040020
+38051000
+38059010
+38059090
+38061000
+38062000
+38063000
+38069011
+38069012
+38069019
+38069090
+38070000
+38085200
+38085910
+38085921
+38085922
+38085923
+38085924
+38085925
+38085926
+38085929
+38086100
+38086210
+38086290
+38086910
+38086990
+38089111
+38089119
+38089120
+38089191
+38089192
+38089193
+38089194
+38089195
+38089196
+38089197
+38089199
+38089211
+38089219
+38089220
+38089291
+38089292
+38089293
+38089294
+38089295
+38089296
+38089297
+38089299
+38089311
+38089319
+38089321
+38089322
+38089323
+38089324
+38089325
+38089326
+38089327
+38089328
+38089329
+38089331
+38089332
+38089333
+38089341
+38089349
+38089351
+38089352
+38089359
+38089411
+38089419
+38089421
+38089422
+38089429
+38089911
+38089919
+38089920
+38089991
+38089992
+38089993
+38089994
+38089995
+38089996
+38089999
+38091010
+38091090
+38099110
+38099120
+38099130
+38099141
+38099149
+38099190
+38099211
+38099219
+38099290
+38099311
+38099319
+38099390
+38101010
+38101020
+38109000
+38111100
+38111900
+38112110
+38112120
+38112130
+38112140
+38112150
+38112190
+38112910
+38112920
+38112990
+38119010
+38119090
+38121000
+38122000
+38123100
+38123911
+38123912
+38123919
+38123921
+38123929
+38130010
+38130020
+38130030
+38130040
+38130090
+38140010
+38140020
+38140030
+38140090
+38151100
+38151210
+38151220
+38151290
+38151900
+38159010
+38159091
+38159092
+38159093
+38159099
+38160011
+38160012
+38160019
+38160021
+38160029
+38160090
+38170010
+38170020
+38180010
+38180090
+38190000
+38200000
+38210000
+38221100
+38221200
+38221300
+38221910
+38221920
+38221930
+38221940
+38221990
+38229000
+38231100
+38231200
+38231300
+38231910
+38231990
+38237010
+38237020
+38237040
+38237090
+38241000
+38243000
+38244000
+38245000
+38246000
+38248110
+38248190
+38248210
+38248290
+38248300
+38248400
+38248500
+38248600
+38248700
+38248810
+38248820
+38248900
+38249100
+38249200
+38249911
+38249912
+38249913
+38249914
+38249915
+38249919
+38249921
+38249922
+38249923
+38249924
+38249925
+38249929
+38249931
+38249932
+38249933
+38249934
+38249935
+38249936
+38249939
+38249941
+38249942
+38249943
+38249949
+38249951
+38249952
+38249953
+38249954
+38249959
+38249961
+38249962
+38249969
+38249971
+38249972
+38249973
+38249974
+38249975
+38249976
+38249977
+38249978
+38249979
+38249981
+38249982
+38249983
+38249984
+38249985
+38249986
+38249987
+38249988
+38249989
+38251000
+38252000
+38253000
+38254100
+38254900
+38255000
+38256100
+38256900
+38259000
+38260000
+38271110
+38271190
+38271200
+38271300
+38271400
+38272000
+38273110
+38273190
+38273210
+38273290
+38273900
+38274000
+38275100
+38275900
+38276100
+38276200
+38276300
+38276400
+38276500
+38276800
+38276900
+38279000
+39011020
+39011030
+39012011
+39012019
+39012021
+39012029
+39013010
+39013090
+39014000
+39019010
+39019020
+39019030
+39019040
+39019050
+39019090
+39021010
+39021020
+39022000
+39023000
+39029000
+39031110
+39031120
+39031900
+39032000
+39033010
+39033020
+39039010
+39039020
+39039090
+39041010
+39041020
+39041090
+39042100
+39042200
+39043000
+39044010
+39044090
+39045010
+39045090
+39046110
+39046190
+39046910
+39046990
+39049010
+39049090
+39051200
+39051910
+39051990
+39052100
+39052900
+39053000
+39059130
+39059190
+39059910
+39059920
+39059930
+39059990
+39061000
+39069011
+39069012
+39069019
+39069021
+39069022
+39069029
+39069031
+39069032
+39069039
+39069051
+39069052
+39069053
+39069054
+39069059
+39069061
+39069062
+39069063
+39069064
+39069065
+39069069
+39071010
+39071020
+39071031
+39071039
+39071041
+39071042
+39071049
+39071091
+39071099
+39072100
+39072911
+39072912
+39072920
+39072931
+39072939
+39072941
+39072942
+39072949
+39072991
+39072992
+39072999
+39073011
+39073019
+39073021
+39073022
+39073029
+39074010
+39074020
+39074090
+39075010
+39075090
+39076100
+39076900
+39077000
+39079100
+39079911
+39079912
+39079919
+39079991
+39079992
+39079993
+39079994
+39079995
+39079999
+39081011
+39081012
+39081013
+39081014
+39081019
+39081021
+39081022
+39081023
+39081025
+39081026
+39081029
+39089010
+39089020
+39089090
+39091000
+39092011
+39092019
+39092021
+39092029
+39093100
+39093900
+39094011
+39094019
+39094091
+39094099
+39095011
+39095012
+39095019
+39095021
+39095029
+39100011
+39100012
+39100013
+39100019
+39100021
+39100029
+39100030
+39100090
+39111010
+39111021
+39111029
+39112000
+39119011
+39119012
+39119013
+39119014
+39119019
+39119021
+39119022
+39119023
+39119024
+39119025
+39119026
+39119027
+39119029
+39121110
+39121120
+39121200
+39122010
+39122021
+39122029
+39123111
+39123119
+39123121
+39123129
+39123910
+39123920
+39123930
+39123990
+39129010
+39129020
+39129031
+39129039
+39129040
+39129090
+39131000
+39139011
+39139012
+39139019
+39139020
+39139030
+39139040
+39139050
+39139060
+39139090
+39140011
+39140019
+39140090
+39151000
+39152000
+39153000
+39159000
+39161000
+39162000
+39169010
+39169090
+39171010
+39171021
+39171029
+39172100
+39172210
+39172290
+39172300
+39172900
+39173100
+39173210
+39173221
+39173229
+39173230
+39173240
+39173251
+39173259
+39173290
+39173300
+39173900
+39174010
+39174090
+39181000
+39189000
+39191010
+39191020
+39191090
+39199010
+39199020
+39199090
+39201010
+39201091
+39201099
+39202011
+39202012
+39202019
+39202090
+39203000
+39204310
+39204390
+39204900
+39205100
+39205900
+39206100
+39206211
+39206219
+39206291
+39206299
+39206300
+39206900
+39207100
+39207310
+39207390
+39207910
+39207990
+39209100
+39209200
+39209300
+39209400
+39209910
+39209920
+39209930
+39209940
+39209950
+39209990
+39211100
+39211200
+39211310
+39211390
+39211400
+39211900
+39219011
+39219012
+39219013
+39219019
+39219020
+39219090
+39221000
+39222000
+39229000
+39231010
+39231090
+39232110
+39232190
+39232910
+39232990
+39233010
+39233090
+39234000
+39235000
+39239010
+39239090
+39241000
+39249000
+39251000
+39252000
+39253000
+39259010
+39259090
+39261000
+39262000
+39263000
+39264000
+39269010
+39269021
+39269022
+39269030
+39269040
+39269050
+39269061
+39269069
+39269090
+40011000
+40012100
+40012200
+40012910
+40012920
+40012990
+40013000
+40021110
+40021120
+40021911
+40021912
+40021919
+40021920
+40022010
+40022091
+40022099
+40023100
+40023900
+40024100
+40024900
+40025100
+40025900
+40026000
+40027000
+40028000
+40029100
+40029910
+40029920
+40029930
+40029990
+40030000
+40040000
+40051010
+40051090
+40052000
+40059110
+40059190
+40059910
+40059990
+40061000
+40069000
+40070011
+40070019
+40070020
+40081100
+40081900
+40082100
+40082900
+40091100
+40091210
+40091290
+40092110
+40092190
+40092210
+40092290
+40093100
+40093210
+40093290
+40094100
+40094210
+40094290
+40101100
+40101200
+40101900
+40103100
+40103200
+40103300
+40103400
+40103500
+40103600
+40103900
+40111000
+40112010
+40112090
+40113000
+40114000
+40115000
+40117010
+40117090
+40118010
+40118020
+40118090
+40119010
+40119090
+40121100
+40121200
+40121300
+40121900
+40122000
+40129010
+40129090
+40131010
+40131090
+40132000
+40139000
+40141000
+40149010
+40149090
+40151200
+40151900
+40159000
+40161010
+40161090
+40169100
+40169200
+40169300
+40169400
+40169510
+40169590
+40169910
+40169990
+40170000
+41012000
+41015010
+41015020
+41015030
+41019010
+41019020
+41019030
+41021000
+41022100
+41022900
+41032000
+41033000
+41039000
+41041111
+41041112
+41041113
+41041114
+41041119
+41041121
+41041122
+41041123
+41041124
+41041129
+41041910
+41041920
+41041930
+41041940
+41041990
+41044110
+41044120
+41044130
+41044190
+41044910
+41044920
+41044990
+41051010
+41051021
+41051029
+41051090
+41053000
+41062110
+41062121
+41062129
+41062190
+41062200
+41063110
+41063190
+41063200
+41064000
+41069100
+41069200
+41071110
+41071120
+41071190
+41071210
+41071220
+41071290
+41071910
+41071920
+41071990
+41079110
+41079190
+41079210
+41079290
+41079910
+41079990
+41120000
+41131010
+41131090
+41132000
+41133000
+41139000
+41141000
+41142010
+41142020
+41151000
+41152000
+42010010
+42010090
+42021100
+42021210
+42021220
+42021900
+42022100
+42022210
+42022220
+42022900
+42023100
+42023200
+42023900
+42029100
+42029200
+42029900
+42031000
+42032100
+42032900
+42033000
+42034000
+42050000
+42060000
+43011000
+43013000
+43016000
+43018000
+43019000
+43021100
+43021910
+43021990
+43022000
+43023000
+43031000
+43039000
+43040000
+44011100
+44011200
+44012100
+44012200
+44013100
+44013200
+44013900
+44014100
+44014900
+44021000
+44022000
+44029000
+44031100
+44031200
+44032100
+44032200
+44032300
+44032400
+44032500
+44032600
+44034100
+44034200
+44034900
+44039100
+44039300
+44039400
+44039500
+44039600
+44039700
+44039800
+44039900
+44041000
+44042000
+44050000
+44061100
+44061200
+44069100
+44069200
+44071100
+44071200
+44071300
+44071400
+44071900
+44072100
+44072200
+44072300
+44072500
+44072600
+44072700
+44072800
+44072910
+44072920
+44072930
+44072940
+44072950
+44072960
+44072970
+44072990
+44079100
+44079200
+44079300
+44079400
+44079500
+44079600
+44079700
+44079920
+44079930
+44079960
+44079970
+44079990
+44081010
+44081091
+44081099
+44083110
+44083190
+44083910
+44083991
+44083992
+44083999
+44089010
+44089090
+44091000
+44092100
+44092200
+44092900
+44101110
+44101121
+44101129
+44101190
+44101210
+44101290
+44101911
+44101919
+44101991
+44101992
+44101999
+44109000
+44111210
+44111290
+44111310
+44111391
+44111399
+44111410
+44111490
+44119210
+44119290
+44119310
+44119390
+44119410
+44119490
+44121000
+44123100
+44123300
+44123400
+44123900
+44124100
+44124200
+44124900
+44125100
+44125200
+44125900
+44129100
+44129200
+44129900
+44130000
+44141000
+44149000
+44151000
+44152000
+44160010
+44160090
+44170010
+44170020
+44170090
+44181100
+44181900
+44182100
+44182900
+44183000
+44184000
+44185000
+44187300
+44187400
+44187500
+44187900
+44188100
+44188200
+44188300
+44188900
+44189100
+44189200
+44189900
+44191100
+44191200
+44191900
+44192000
+44199000
+44201100
+44201900
+44209000
+44211000
+44212000
+44219100
+44219900
+45011000
+45019000
+45020000
+45031000
+45039000
+45041000
+45049000
+46012100
+46012200
+46012900
+46019200
+46019300
+46019400
+46019900
+46021100
+46021200
+46021900
+46029000
+47010000
+47020000
+47031100
+47031900
+47032110
+47032190
+47032900
+47041100
+47041900
+47042100
+47042900
+47050000
+47061000
+47062000
+47063000
+47069100
+47069200
+47069300
+47071000
+47072000
+47073000
+47079000
+48010020
+48010030
+48010090
+48021000
+48022010
+48022090
+48024010
+48024090
+48025410
+48025491
+48025499
+48025510
+48025591
+48025592
+48025599
+48025610
+48025691
+48025692
+48025693
+48025699
+48025710
+48025791
+48025792
+48025793
+48025799
+48025810
+48025891
+48025892
+48025899
+48026110
+48026191
+48026192
+48026199
+48026210
+48026291
+48026292
+48026299
+48026910
+48026991
+48026992
+48026999
+48030010
+48030090
+48041100
+48041900
+48042100
+48042900
+48043110
+48043190
+48043910
+48043990
+48044100
+48044200
+48044900
+48045100
+48045200
+48045910
+48045990
+48051100
+48051200
+48051900
+48052400
+48052500
+48053000
+48054010
+48054090
+48055000
+48059100
+48059210
+48059290
+48059300
+48061000
+48062000
+48063000
+48064000
+48070000
+48081000
+48084000
+48089000
+48092000
+48099000
+48101310
+48101381
+48101382
+48101389
+48101391
+48101399
+48101410
+48101481
+48101482
+48101489
+48101490
+48101910
+48101981
+48101982
+48101989
+48101991
+48101999
+48102210
+48102290
+48102910
+48102990
+48103110
+48103190
+48103210
+48103290
+48103910
+48103990
+48109210
+48109290
+48109910
+48109990
+48111010
+48111090
+48114110
+48114190
+48114910
+48114990
+48115110
+48115121
+48115122
+48115123
+48115128
+48115129
+48115130
+48115910
+48115921
+48115922
+48115923
+48115929
+48115930
+48116010
+48116090
+48119011
+48119019
+48119020
+48119090
+48120000
+48131000
+48132000
+48139000
+48142000
+48149000
+48162000
+48169010
+48169090
+48171000
+48172000
+48173000
+48181000
+48182000
+48183000
+48185000
+48189010
+48189090
+48191000
+48192000
+48193000
+48194000
+48195000
+48196000
+48201000
+48202000
+48203000
+48204000
+48205000
+48209000
+48211000
+48219000
+48221000
+48229000
+48232010
+48232091
+48232099
+48234000
+48236100
+48236900
+48237000
+48239010
+48239020
+48239091
+48239099
+49011000
+49019100
+49019900
+49021000
+49029000
+49030000
+49040000
+49052000
+49059000
+49060000
+49070010
+49070020
+49070030
+49070090
+49081000
+49089000
+49090000
+49100000
+49111010
+49111090
+49119100
+49119900
+50010000
+50020000
+50030010
+50030090
+50040000
+50050000
+50060000
+50071010
+50071090
+50072010
+50072090
+50079000
+51011110
+51011190
+51011900
+51012100
+51012900
+51013000
+51021100
+51021900
+51022000
+51031000
+51032000
+51033000
+51040000
+51051000
+51052100
+51052910
+51052991
+51052999
+51053100
+51053900
+51054000
+51061000
+51062000
+51071011
+51071019
+51071090
+51072000
+51081000
+51082000
+51091000
+51099000
+51100000
+51111110
+51111120
+51111900
+51112000
+51113010
+51113090
+51119000
+51121100
+51121910
+51121920
+51122010
+51122020
+51123010
+51123020
+51129000
+51130011
+51130012
+51130013
+51130020
+52010010
+52010020
+52010090
+52021000
+52029100
+52029900
+52030000
+52041111
+52041112
+52041120
+52041131
+52041132
+52041140
+52041911
+52041912
+52041920
+52041931
+52041932
+52041940
+52042000
+52051100
+52051200
+52051310
+52051390
+52051400
+52051500
+52052100
+52052200
+52052310
+52052390
+52052400
+52052600
+52052700
+52052800
+52053100
+52053200
+52053300
+52053400
+52053500
+52054100
+52054200
+52054300
+52054400
+52054600
+52054700
+52054800
+52061100
+52061200
+52061300
+52061400
+52061500
+52062100
+52062200
+52062300
+52062400
+52062500
+52063100
+52063200
+52063300
+52063400
+52063500
+52064100
+52064200
+52064300
+52064400
+52064500
+52071000
+52079000
+52081100
+52081200
+52081300
+52081900
+52082100
+52082200
+52082300
+52082900
+52083100
+52083200
+52083300
+52083900
+52084100
+52084200
+52084300
+52084900
+52085100
+52085200
+52085910
+52085990
+52091100
+52091200
+52091900
+52092100
+52092200
+52092900
+52093100
+52093200
+52093900
+52094100
+52094210
+52094290
+52094300
+52094900
+52095100
+52095200
+52095900
+52101100
+52101910
+52101990
+52102100
+52102910
+52102990
+52103100
+52103200
+52103900
+52104100
+52104910
+52104990
+52105100
+52105910
+52105990
+52111100
+52111200
+52111900
+52112010
+52112020
+52112090
+52113100
+52113200
+52113900
+52114100
+52114210
+52114290
+52114300
+52114900
+52115100
+52115200
+52115900
+52121100
+52121200
+52121300
+52121400
+52121500
+52122100
+52122200
+52122300
+52122400
+52122500
+53011000
+53012110
+53012120
+53012910
+53012990
+53013000
+53021000
+53029000
+53031010
+53031090
+53039010
+53039090
+53050010
+53050090
+53061000
+53062000
+53071010
+53071090
+53072010
+53072090
+53081000
+53082000
+53089000
+53091100
+53091900
+53092100
+53092900
+53101010
+53101090
+53109000
+53110000
+54011011
+54011012
+54011090
+54012011
+54012012
+54012090
+54021100
+54021910
+54021990
+54022010
+54022090
+54023111
+54023119
+54023190
+54023211
+54023219
+54023290
+54023310
+54023320
+54023390
+54023400
+54023900
+54024400
+54024510
+54024520
+54024590
+54024600
+54024710
+54024720
+54024790
+54024800
+54024910
+54024990
+54025110
+54025190
+54025200
+54025300
+54025900
+54026110
+54026190
+54026200
+54026300
+54026900
+54031000
+54033110
+54033190
+54033200
+54033300
+54033900
+54034100
+54034200
+54034900
+54041100
+54041200
+54041911
+54041919
+54041990
+54049000
+54050000
+54060010
+54060020
+54071011
+54071019
+54071021
+54071029
+54072000
+54073000
+54074100
+54074200
+54074300
+54074400
+54075100
+54075210
+54075220
+54075300
+54075400
+54076100
+54076900
+54077100
+54077200
+54077300
+54077400
+54078100
+54078200
+54078300
+54078400
+54079100
+54079200
+54079300
+54079400
+54081000
+54082100
+54082200
+54082300
+54082400
+54083100
+54083200
+54083300
+54083400
+55011100
+55011900
+55012000
+55013000
+55014000
+55019000
+55021000
+55029010
+55029090
+55031100
+55031910
+55031990
+55032010
+55032090
+55033000
+55034000
+55039010
+55039020
+55039090
+55041000
+55049010
+55049090
+55051000
+55052000
+55061000
+55062000
+55063000
+55064000
+55069000
+55070000
+55081000
+55082000
+55091100
+55091210
+55091290
+55092100
+55092200
+55093100
+55093200
+55094100
+55094200
+55095100
+55095200
+55095300
+55095900
+55096100
+55096200
+55096900
+55099100
+55099200
+55099900
+55101111
+55101112
+55101113
+55101119
+55101190
+55101211
+55101212
+55101213
+55101219
+55101290
+55102011
+55102012
+55102013
+55102019
+55102090
+55103011
+55103012
+55103013
+55103019
+55103090
+55109011
+55109012
+55109013
+55109019
+55109090
+55111000
+55112000
+55113000
+55121100
+55121900
+55122100
+55122900
+55129110
+55129190
+55129910
+55129990
+55131100
+55131200
+55131300
+55131900
+55132100
+55132310
+55132390
+55132900
+55133100
+55133911
+55133919
+55133990
+55134100
+55134911
+55134919
+55134990
+55141100
+55141200
+55141910
+55141990
+55142100
+55142200
+55142300
+55142900
+55143011
+55143012
+55143019
+55143090
+55144100
+55144200
+55144300
+55144900
+55151100
+55151200
+55151300
+55151900
+55152100
+55152200
+55152900
+55159100
+55159910
+55159990
+55161100
+55161200
+55161300
+55161400
+55162100
+55162200
+55162300
+55162400
+55163100
+55163200
+55163300
+55163400
+55164100
+55164200
+55164300
+55164400
+55169100
+55169200
+55169300
+55169400
+56012110
+56012190
+56012211
+56012219
+56012291
+56012299
+56012900
+56013010
+56013090
+56021000
+56022100
+56022900
+56029000
+56031110
+56031120
+56031130
+56031140
+56031190
+56031210
+56031220
+56031230
+56031240
+56031250
+56031290
+56031310
+56031320
+56031330
+56031340
+56031350
+56031390
+56031410
+56031420
+56031430
+56031440
+56031490
+56039110
+56039120
+56039130
+56039190
+56039210
+56039220
+56039230
+56039240
+56039290
+56039310
+56039320
+56039330
+56039340
+56039390
+56039410
+56039420
+56039430
+56039490
+56041000
+56049010
+56049021
+56049022
+56049090
+56050010
+56050020
+56050090
+56060000
+56072100
+56072900
+56074100
+56074900
+56075011
+56075019
+56075090
+56079010
+56079020
+56079090
+56081100
+56081900
+56089000
+56090010
+56090090
+57011011
+57011012
+57011020
+57019000
+57021000
+57022000
+57023100
+57023200
+57023900
+57024100
+57024200
+57024900
+57025010
+57025020
+57025090
+57029100
+57029200
+57029900
+57031000
+57032100
+57032900
+57033100
+57033900
+57039000
+57041000
+57042000
+57049000
+57050000
+58011000
+58012100
+58012200
+58012300
+58012600
+58012700
+58013100
+58013200
+58013300
+58013600
+58013700
+58019000
+58021000
+58022000
+58023000
+58030010
+58030090
+58041010
+58041090
+58042100
+58042910
+58042990
+58043010
+58043090
+58050010
+58050020
+58050090
+58061000
+58062000
+58063100
+58063200
+58063900
+58064000
+58071000
+58079000
+58081000
+58089000
+58090000
+58101000
+58109100
+58109200
+58109900
+58110000
+59011000
+59019000
+59021010
+59021090
+59022000
+59029000
+59031000
+59032000
+59039010
+59039090
+59041000
+59049000
+59050000
+59061000
+59069100
+59069900
+59070000
+59080000
+59090000
+59100000
+59111000
+59112010
+59112090
+59113100
+59113200
+59114000
+59119000
+60011010
+60011020
+60011090
+60012100
+60012200
+60012900
+60019100
+60019200
+60019900
+60024010
+60024020
+60024090
+60029010
+60029020
+60029090
+60031000
+60032000
+60033000
+60034000
+60039000
+60041011
+60041012
+60041013
+60041014
+60041031
+60041032
+60041033
+60041034
+60041041
+60041042
+60041043
+60041044
+60041091
+60041092
+60041093
+60041094
+60049010
+60049030
+60049040
+60049090
+60052100
+60052200
+60052300
+60052400
+60053500
+60053600
+60053700
+60053800
+60053900
+60054100
+60054200
+60054300
+60054400
+60059010
+60059090
+60061000
+60062100
+60062200
+60062300
+60062400
+60063110
+60063120
+60063130
+60063190
+60063210
+60063220
+60063230
+60063290
+60063310
+60063320
+60063330
+60063390
+60063410
+60063420
+60063430
+60063490
+60064100
+60064200
+60064300
+60064400
+60069000
+61012000
+61013000
+61019010
+61019090
+61021000
+61022000
+61023000
+61029000
+61031010
+61031020
+61031090
+61032200
+61032300
+61032910
+61032990
+61033100
+61033200
+61033300
+61033900
+61034100
+61034200
+61034300
+61034900
+61041300
+61041910
+61041920
+61041990
+61042200
+61042300
+61042910
+61042990
+61043100
+61043200
+61043300
+61043900
+61044100
+61044200
+61044300
+61044400
+61044900
+61045100
+61045200
+61045300
+61045900
+61046100
+61046200
+61046300
+61046900
+61051000
+61052000
+61059000
+61061000
+61062000
+61069000
+61071100
+61071200
+61071900
+61072100
+61072200
+61072900
+61079100
+61079910
+61079990
+61081100
+61081900
+61082100
+61082200
+61082900
+61083100
+61083200
+61083900
+61089100
+61089200
+61089900
+61091000
+61099000
+61101100
+61101200
+61101900
+61102000
+61103000
+61109000
+61112000
+61113000
+61119010
+61119090
+61121100
+61121200
+61121900
+61122000
+61123100
+61123900
+61124100
+61124900
+61130000
+61142000
+61143000
+61149010
+61149090
+61151011
+61151012
+61151013
+61151014
+61151019
+61151021
+61151022
+61151029
+61151091
+61151092
+61151093
+61151099
+61152100
+61152200
+61152910
+61152920
+61152990
+61153010
+61153020
+61153090
+61159400
+61159500
+61159600
+61159900
+61161000
+61169100
+61169200
+61169300
+61169900
+61171000
+61178010
+61178090
+61179000
+62012000
+62013000
+62014000
+62019000
+62022000
+62023000
+62024000
+62029000
+62031100
+62031200
+62031900
+62032200
+62032300
+62032910
+62032990
+62033100
+62033200
+62033300
+62033900
+62034100
+62034200
+62034300
+62034900
+62041100
+62041200
+62041300
+62041900
+62042100
+62042200
+62042300
+62042900
+62043100
+62043200
+62043300
+62043900
+62044100
+62044200
+62044300
+62044400
+62044900
+62045100
+62045200
+62045300
+62045900
+62046100
+62046200
+62046300
+62046900
+62052000
+62053000
+62059010
+62059090
+62061000
+62062000
+62063000
+62064000
+62069000
+62071100
+62071900
+62072100
+62072200
+62072900
+62079100
+62079910
+62079990
+62081100
+62081900
+62082100
+62082200
+62082900
+62089100
+62089200
+62089900
+62092000
+62093000
+62099010
+62099090
+62101000
+62102000
+62103000
+62104000
+62105000
+62111100
+62111200
+62112000
+62113200
+62113300
+62113910
+62113990
+62114200
+62114300
+62114900
+62121000
+62122000
+62123000
+62129000
+62132000
+62139010
+62139090
+62141000
+62142000
+62143000
+62144000
+62149010
+62149090
+62151000
+62152000
+62159000
+62160000
+62171000
+62179000
+63011000
+63012000
+63013000
+63014000
+63019000
+63021000
+63022100
+63022200
+63022900
+63023100
+63023200
+63023900
+63024000
+63025100
+63025300
+63025910
+63025990
+63026000
+63029100
+63029300
+63029910
+63029990
+63031200
+63031910
+63031990
+63039100
+63039200
+63039900
+63041100
+63041910
+63041990
+63042000
+63049100
+63049200
+63049300
+63049900
+63051000
+63052000
+63053200
+63053310
+63053390
+63053900
+63059000
+63061200
+63061910
+63061990
+63062200
+63062910
+63062990
+63063010
+63063090
+63064010
+63064090
+63069000
+63071000
+63072000
+63079010
+63079020
+63079090
+63080000
+63090010
+63090090
+63101000
+63109000
+64011000
+64019200
+64019910
+64019990
+64021200
+64021900
+64022000
+64029110
+64029190
+64029910
+64029990
+64031200
+64031900
+64032000
+64034000
+64035110
+64035190
+64035910
+64035990
+64039110
+64039190
+64039910
+64039990
+64041100
+64041900
+64042000
+64051010
+64051020
+64051090
+64052000
+64059000
+64061000
+64062000
+64069010
+64069020
+64069090
+65010000
+65020010
+65020090
+65040010
+65040090
+65050011
+65050012
+65050019
+65050021
+65050022
+65050029
+65050031
+65050032
+65050039
+65050090
+65061010
+65061090
+65069100
+65069900
+65070000
+66011000
+66019110
+66019190
+66019900
+66020000
+66032000
+66039000
+67010000
+67021000
+67029000
+67030000
+67041100
+67041900
+67042000
+67049000
+68010000
+68021000
+68022100
+68022300
+68022900
+68029100
+68029200
+68029310
+68029390
+68029910
+68029990
+68030000
+68041000
+68042111
+68042119
+68042190
+68042211
+68042219
+68042290
+68042300
+68043000
+68051000
+68052000
+68053010
+68053020
+68053090
+68061000
+68062000
+68069010
+68069090
+68071000
+68079000
+68080000
+68091100
+68091900
+68099000
+68101100
+68101900
+68109100
+68109900
+68114000
+68118100
+68118200
+68118900
+68128000
+68129100
+68129910
+68129920
+68129930
+68129990
+68132000
+68138110
+68138190
+68138910
+68138990
+68141000
+68149000
+68151100
+68151200
+68151300
+68151900
+68152000
+68159110
+68159190
+68159911
+68159912
+68159913
+68159914
+68159919
+68159990
+69010000
+69021011
+69021018
+69021019
+69021090
+69022010
+69022091
+69022092
+69022093
+69022099
+69029010
+69029020
+69029030
+69029040
+69029090
+69031011
+69031012
+69031019
+69031020
+69031030
+69031040
+69031090
+69032010
+69032020
+69032030
+69032090
+69039011
+69039012
+69039019
+69039091
+69039092
+69039099
+69041000
+69049000
+69051000
+69059000
+69060000
+69072100
+69072200
+69072300
+69073000
+69074000
+69091100
+69091210
+69091220
+69091230
+69091290
+69091910
+69091920
+69091930
+69091990
+69099000
+69101000
+69109000
+69111010
+69111090
+69119000
+69120000
+69131000
+69139000
+69141000
+69149000
+70010000
+70021000
+70022000
+70023100
+70023200
+70023900
+70031200
+70031900
+70032000
+70033000
+70042000
+70049000
+70051000
+70052100
+70052900
+70053000
+70060000
+70071100
+70071900
+70072100
+70072900
+70080000
+70091000
+70099100
+70099200
+70101000
+70102000
+70109011
+70109012
+70109021
+70109022
+70109090
+70111010
+70111021
+70111029
+70111090
+70112000
+70119000
+70131000
+70132200
+70132800
+70133300
+70133700
+70134100
+70134210
+70134290
+70134900
+70139110
+70139190
+70139900
+70140000
+70151010
+70151091
+70151092
+70159010
+70159020
+70159030
+70159090
+70161000
+70169000
+70171000
+70172000
+70179000
+70181010
+70181020
+70181090
+70182000
+70189000
+70191100
+70191210
+70191290
+70191300
+70191400
+70191500
+70191900
+70196100
+70196200
+70196300
+70196400
+70196500
+70196600
+70196900
+70197100
+70197200
+70197310
+70197390
+70198000
+70199000
+70200010
+70200090
+71011000
+71012100
+71012200
+71021000
+71022100
+71022900
+71023100
+71023900
+71031000
+71039100
+71039900
+71041000
+71042100
+71042900
+71049100
+71049900
+71051000
+71059000
+71061000
+71069100
+71069210
+71069220
+71069290
+71070000
+71081100
+71081210
+71081290
+71081310
+71081390
+71082000
+71090000
+71101100
+71101910
+71101990
+71102100
+71102900
+71103100
+71103900
+71104100
+71104900
+71110000
+71123010
+71123020
+71123090
+71129100
+71129200
+71129900
+71131100
+71131900
+71132000
+71141100
+71141900
+71142000
+71151000
+71159000
+71161000
+71162010
+71162020
+71162090
+71171100
+71171900
+71179000
+71181010
+71181090
+71189000
+72011000
+72012000
+72015000
+72021100
+72021900
+72022100
+72022900
+72023000
+72024100
+72024900
+72025000
+72026000
+72027000
+72028000
+72029100
+72029200
+72029300
+72029910
+72029990
+72031000
+72039000
+72041000
+72042100
+72042900
+72043000
+72044100
+72044900
+72045000
+72051000
+72052100
+72052910
+72052920
+72052990
+72061000
+72069000
+72071110
+72071190
+72071200
+72071900
+72072000
+72081000
+72082500
+72082610
+72082690
+72082710
+72082790
+72083610
+72083690
+72083700
+72083810
+72083890
+72083910
+72083990
+72084000
+72085100
+72085200
+72085300
+72085400
+72089000
+72091500
+72091600
+72091700
+72091800
+72092500
+72092600
+72092700
+72092800
+72099000
+72101100
+72101200
+72102000
+72103010
+72103090
+72104110
+72104190
+72104910
+72104990
+72105000
+72106100
+72106911
+72106919
+72106990
+72107010
+72107020
+72109000
+72111300
+72111400
+72111900
+72112300
+72112910
+72112920
+72119010
+72119090
+72121000
+72122010
+72122090
+72123000
+72124010
+72124021
+72124029
+72125010
+72125090
+72126000
+72131000
+72132000
+72139110
+72139190
+72139910
+72139990
+72141010
+72141090
+72142000
+72143000
+72149100
+72149910
+72149990
+72151000
+72155000
+72159010
+72159090
+72161000
+72162100
+72162200
+72163100
+72163200
+72163300
+72164010
+72164090
+72165000
+72166110
+72166190
+72166910
+72166990
+72169100
+72169900
+72171011
+72171019
+72171090
+72172010
+72172090
+72173010
+72173090
+72179000
+72181000
+72189100
+72189900
+72191100
+72191200
+72191300
+72191400
+72192100
+72192200
+72192300
+72192400
+72193100
+72193200
+72193300
+72193400
+72193500
+72199010
+72199090
+72201100
+72201210
+72201220
+72201290
+72202010
+72202090
+72209000
+72210000
+72221100
+72221910
+72221990
+72222000
+72223000
+72224010
+72224090
+72230000
+72241000
+72249000
+72251100
+72251900
+72253000
+72254010
+72254020
+72254090
+72255010
+72255090
+72259100
+72259200
+72259910
+72259990
+72261100
+72261900
+72262010
+72262090
+72269100
+72269200
+72269900
+72271000
+72272000
+72279000
+72281010
+72281090
+72282000
+72283000
+72284000
+72285000
+72286000
+72287000
+72288000
+72292000
+72299000
+73011000
+73012000
+73021010
+73021090
+73023000
+73024000
+73029000
+73030000
+73041100
+73041900
+73042200
+73042310
+73042390
+73042400
+73042910
+73042931
+73042939
+73042990
+73043110
+73043190
+73043910
+73043920
+73043990
+73044110
+73044190
+73044900
+73045111
+73045119
+73045190
+73045910
+73045990
+73049011
+73049019
+73049090
+73051100
+73051200
+73051900
+73052000
+73053100
+73053900
+73059000
+73061100
+73061900
+73062100
+73062900
+73063010
+73063090
+73064000
+73065000
+73066100
+73066900
+73069010
+73069020
+73069090
+73071100
+73071910
+73071920
+73071990
+73072100
+73072200
+73072300
+73072900
+73079100
+73079200
+73079300
+73079900
+73081000
+73082000
+73083000
+73084000
+73089010
+73089090
+73090010
+73090020
+73090090
+73101010
+73101090
+73102110
+73102190
+73102910
+73102920
+73102990
+73110000
+73121010
+73121090
+73129000
+73130000
+73141200
+73141400
+73141900
+73142000
+73143100
+73143900
+73144100
+73144200
+73144900
+73145000
+73151110
+73151190
+73151210
+73151290
+73151900
+73152000
+73158100
+73158200
+73158900
+73159000
+73160000
+73170010
+73170020
+73170030
+73170090
+73181100
+73181200
+73181300
+73181400
+73181500
+73181600
+73181900
+73182100
+73182200
+73182300
+73182400
+73182900
+73194000
+73199000
+73201000
+73202010
+73202090
+73209000
+73211100
+73211200
+73211900
+73218100
+73218200
+73218900
+73219000
+73221100
+73221900
+73229010
+73229090
+73231000
+73239100
+73239200
+73239300
+73239400
+73239900
+73241000
+73242100
+73242900
+73249000
+73251000
+73259100
+73259910
+73259990
+73261100
+73261900
+73262000
+73269010
+73269020
+73269090
+74010000
+74020000
+74031100
+74031200
+74031300
+74031900
+74032100
+74032200
+74032900
+74040000
+74050000
+74061010
+74061020
+74061090
+74062000
+74071010
+74071021
+74071029
+74072110
+74072120
+74072910
+74072921
+74072929
+74081100
+74081900
+74082100
+74082200
+74082912
+74082913
+74082919
+74082990
+74091100
+74091900
+74092100
+74092900
+74093111
+74093119
+74093190
+74093900
+74094011
+74094019
+74094090
+74099000
+74101112
+74101113
+74101119
+74101190
+74101200
+74102110
+74102120
+74102130
+74102190
+74102200
+74111010
+74111090
+74112110
+74112190
+74112210
+74112290
+74112910
+74112990
+74121000
+74122000
+74130000
+74151000
+74152100
+74152900
+74153300
+74153900
+74181000
+74182000
+74192000
+74198010
+74198020
+74198030
+74198040
+74198090
+75011000
+75012000
+75021010
+75021090
+75022000
+75030000
+75040010
+75040090
+75051110
+75051121
+75051129
+75051210
+75051221
+75051229
+75052100
+75052210
+75052290
+75061000
+75062000
+75071100
+75071200
+75072000
+75081000
+75089010
+75089090
+76011000
+76012000
+76020000
+76031000
+76032000
+76041010
+76041021
+76041029
+76042100
+76042911
+76042919
+76042920
+76051110
+76051190
+76051910
+76051990
+76052110
+76052190
+76052910
+76052990
+76061110
+76061190
+76061210
+76061220
+76061230
+76061290
+76069100
+76069200
+76071110
+76071120
+76071190
+76071910
+76071990
+76072000
+76081000
+76082010
+76082090
+76090000
+76101000
+76109000
+76110000
+76121000
+76129011
+76129012
+76129019
+76129020
+76129090
+76130000
+76141010
+76141090
+76149010
+76149090
+76151000
+76152000
+76161000
+76169100
+76169900
+78011011
+78011019
+78011090
+78019100
+78019900
+78020000
+78041100
+78041900
+78042000
+78060010
+78060020
+78060090
+79011111
+79011119
+79011191
+79011199
+79011210
+79011290
+79012010
+79012090
+79020000
+79031000
+79039000
+79040000
+79050000
+79070010
+79070090
+80011000
+80012000
+80020000
+80030000
+80070010
+80070020
+80070030
+80070090
+81011000
+81019400
+81019600
+81019700
+81019910
+81019990
+81021000
+81029400
+81029500
+81029600
+81029700
+81029900
+81032000
+81033000
+81039100
+81039900
+81041100
+81041900
+81042000
+81043000
+81049000
+81052010
+81052021
+81052029
+81052090
+81053000
+81059010
+81059090
+81061000
+81069000
+81082000
+81083000
+81089000
+81092100
+81092900
+81093100
+81093900
+81099100
+81099900
+81101010
+81101020
+81102000
+81109000
+81110010
+81110020
+81110090
+81121200
+81121300
+81121900
+81122110
+81122120
+81122200
+81122900
+81123100
+81123900
+81124100
+81124900
+81125100
+81125200
+81125900
+81126100
+81126900
+81129200
+81129900
+81130010
+81130090
+82011000
+82013000
+82014000
+82015000
+82016000
+82019000
+82021000
+82022000
+82023100
+82023900
+82024000
+82029100
+82029910
+82029990
+82031010
+82031090
+82032010
+82032090
+82033000
+82034000
+82041100
+82041200
+82042000
+82051000
+82052000
+82053000
+82054000
+82055100
+82055900
+82056000
+82057000
+82059000
+82060000
+82071300
+82071910
+82071990
+82072000
+82073000
+82074010
+82074020
+82075011
+82075019
+82075090
+82076000
+82077010
+82077020
+82077090
+82078000
+82079000
+82081000
+82082000
+82083000
+82084000
+82089000
+82090011
+82090019
+82090090
+82100010
+82100090
+82111000
+82119100
+82119210
+82119220
+82119290
+82119310
+82119320
+82119390
+82119400
+82119500
+82121010
+82121020
+82122010
+82122020
+82129000
+82130000
+82141000
+82142000
+82149010
+82149090
+82151000
+82152000
+82159100
+82159910
+82159990
+83011000
+83012000
+83013000
+83014000
+83015000
+83016000
+83017000
+83021000
+83022000
+83023000
+83024100
+83024200
+83024900
+83025000
+83026000
+83030000
+83040000
+83051000
+83052000
+83059000
+83061000
+83062100
+83062900
+83063000
+83071010
+83071090
+83079000
+83081000
+83082000
+83089010
+83089020
+83089090
+83091000
+83099000
+83100000
+83111000
+83112000
+83113000
+83119000
+84011000
+84012000
+84013000
+84014000
+84021100
+84021200
+84021900
+84022000
+84029000
+84031010
+84031090
+84039000
+84041010
+84041020
+84042000
+84049010
+84049090
+84051000
+84059000
+84061000
+84068100
+84068200
+84069011
+84069019
+84069021
+84069029
+84069090
+84071000
+84072110
+84072190
+84072910
+84072990
+84073110
+84073190
+84073200
+84073310
+84073390
+84073410
+84073490
+84079000
+84081010
+84081090
+84082010
+84082020
+84082030
+84082090
+84089010
+84089090
+84091000
+84099111
+84099112
+84099113
+84099114
+84099115
+84099116
+84099117
+84099118
+84099120
+84099130
+84099140
+84099190
+84099912
+84099914
+84099915
+84099917
+84099921
+84099929
+84099930
+84099941
+84099949
+84099951
+84099959
+84099961
+84099969
+84099971
+84099979
+84099991
+84099999
+84101100
+84101200
+84101300
+84109000
+84111100
+84111200
+84112100
+84112200
+84118100
+84118200
+84119100
+84119900
+84121000
+84122110
+84122190
+84122900
+84123110
+84123190
+84123900
+84128000
+84129010
+84129080
+84129090
+84131100
+84131900
+84132000
+84133010
+84133020
+84133030
+84133090
+84134000
+84135010
+84135090
+84136011
+84136019
+84136090
+84137010
+84137080
+84137090
+84138100
+84138200
+84139110
+84139190
+84139200
+84141000
+84142000
+84143011
+84143019
+84143091
+84143099
+84144010
+84144020
+84144090
+84145110
+84145120
+84145190
+84145910
+84145990
+84146000
+84147000
+84148011
+84148012
+84148013
+84148019
+84148021
+84148022
+84148029
+84148031
+84148032
+84148033
+84148038
+84148039
+84148090
+84149010
+84149020
+84149031
+84149032
+84149033
+84149034
+84149039
+84149040
+84151011
+84151019
+84151090
+84152010
+84152090
+84158110
+84158190
+84158210
+84158290
+84158300
+84159010
+84159020
+84159090
+84161000
+84162010
+84162090
+84163000
+84169000
+84171010
+84171020
+84171090
+84172000
+84178010
+84178020
+84178090
+84179000
+84181000
+84182100
+84182900
+84183000
+84184000
+84185010
+84185090
+84186100
+84186910
+84186920
+84186931
+84186932
+84186940
+84186991
+84186999
+84189100
+84189900
+84191100
+84191200
+84191900
+84192000
+84193300
+84193400
+84193500
+84193900
+84194010
+84194020
+84194090
+84195010
+84195021
+84195022
+84195029
+84195090
+84196000
+84198110
+84198190
+84198911
+84198919
+84198920
+84198930
+84198940
+84198991
+84198999
+84199010
+84199020
+84199031
+84199039
+84199040
+84199090
+84201010
+84201090
+84209100
+84209900
+84211110
+84211190
+84211210
+84211290
+84211910
+84211990
+84212100
+84212200
+84212300
+84212911
+84212919
+84212920
+84212930
+84212990
+84213100
+84213200
+84213910
+84213930
+84213990
+84219110
+84219191
+84219199
+84219910
+84219920
+84219991
+84219999
+84221100
+84221900
+84222000
+84223010
+84223021
+84223022
+84223023
+84223029
+84223030
+84224010
+84224020
+84224030
+84224090
+84229010
+84229090
+84231000
+84232000
+84233011
+84233019
+84233090
+84238110
+84238190
+84238200
+84238900
+84239010
+84239021
+84239029
+84241000
+84242000
+84243010
+84243020
+84243030
+84243090
+84244100
+84244900
+84248221
+84248229
+84248290
+84248910
+84248920
+84248990
+84249010
+84249090
+84251100
+84251910
+84251990
+84253110
+84253190
+84253910
+84253990
+84254100
+84254200
+84254910
+84254990
+84261100
+84261200
+84261900
+84262000
+84263000
+84264110
+84264190
+84264910
+84264990
+84269100
+84269900
+84271011
+84271019
+84271090
+84272010
+84272090
+84279000
+84281000
+84282010
+84282090
+84283100
+84283200
+84283300
+84283910
+84283920
+84283930
+84283990
+84284000
+84286000
+84287000
+84289010
+84289020
+84289030
+84289090
+84291110
+84291190
+84291910
+84291990
+84292010
+84292090
+84293000
+84294000
+84295111
+84295119
+84295121
+84295129
+84295191
+84295192
+84295199
+84295211
+84295212
+84295219
+84295220
+84295290
+84295900
+84301000
+84302000
+84303110
+84303190
+84303910
+84303990
+84304110
+84304120
+84304130
+84304190
+84304910
+84304920
+84304990
+84305000
+84306100
+84306911
+84306919
+84306990
+84311010
+84311090
+84312011
+84312019
+84312090
+84313110
+84313190
+84313900
+84314100
+84314200
+84314310
+84314390
+84314910
+84314921
+84314922
+84314923
+84314929
+84321000
+84322100
+84322900
+84323110
+84323190
+84323910
+84323990
+84324100
+84324200
+84328000
+84329000
+84331100
+84331900
+84332010
+84332090
+84333000
+84334000
+84335100
+84335200
+84335300
+84335911
+84335919
+84335990
+84336010
+84336021
+84336029
+84336090
+84339010
+84339090
+84341000
+84342010
+84342090
+84349000
+84351000
+84359000
+84361000
+84362100
+84362900
+84368000
+84369100
+84369900
+84371000
+84378010
+84378090
+84379000
+84381000
+84382011
+84382019
+84382090
+84383000
+84384000
+84385000
+84386000
+84388010
+84388020
+84388090
+84389000
+84391010
+84391020
+84391030
+84391090
+84392000
+84393010
+84393020
+84393030
+84393090
+84399100
+84399910
+84399990
+84401011
+84401019
+84401020
+84401090
+84409000
+84411010
+84411090
+84412000
+84413010
+84413090
+84414000
+84418000
+84419000
+84423010
+84423020
+84423090
+84424010
+84424020
+84424090
+84425000
+84431110
+84431190
+84431200
+84431310
+84431321
+84431329
+84431390
+84431400
+84431500
+84431600
+84431710
+84431790
+84431910
+84431990
+84433111
+84433112
+84433113
+84433114
+84433115
+84433116
+84433119
+84433191
+84433199
+84433221
+84433222
+84433223
+84433229
+84433231
+84433232
+84433233
+84433234
+84433235
+84433236
+84433237
+84433238
+84433239
+84433240
+84433251
+84433252
+84433259
+84433291
+84433299
+84433910
+84433921
+84433928
+84433929
+84433930
+84433990
+84439110
+84439191
+84439192
+84439199
+84439911
+84439912
+84439919
+84439921
+84439922
+84439923
+84439929
+84439931
+84439932
+84439933
+84439939
+84439941
+84439942
+84439949
+84439950
+84439960
+84439970
+84439980
+84439990
+84440010
+84440020
+84440090
+84451110
+84451120
+84451190
+84451200
+84451300
+84451910
+84451921
+84451922
+84451923
+84451924
+84451925
+84451926
+84451927
+84451929
+84452000
+84453010
+84453090
+84454011
+84454012
+84454018
+84454019
+84454021
+84454029
+84454031
+84454039
+84454040
+84454090
+84459010
+84459020
+84459030
+84459040
+84459090
+84461010
+84461090
+84462100
+84462900
+84463010
+84463020
+84463030
+84463040
+84463090
+84471100
+84471200
+84472010
+84472021
+84472029
+84472030
+84479010
+84479020
+84479090
+84481110
+84481120
+84481190
+84481900
+84482010
+84482020
+84482030
+84482090
+84483100
+84483211
+84483219
+84483220
+84483230
+84483240
+84483250
+84483290
+84483310
+84483390
+84483911
+84483912
+84483917
+84483919
+84483921
+84483922
+84483923
+84483929
+84483991
+84483992
+84483999
+84484200
+84484910
+84484920
+84484990
+84485110
+84485190
+84485910
+84485921
+84485922
+84485929
+84485930
+84485940
+84485990
+84490010
+84490020
+84490080
+84490091
+84490099
+84501100
+84501200
+84501900
+84502010
+84502020
+84502090
+84509010
+84509090
+84511000
+84512100
+84512910
+84512990
+84513010
+84513091
+84513099
+84514010
+84514021
+84514029
+84514090
+84515010
+84515020
+84515090
+84518000
+84519010
+84519090
+84521000
+84522110
+84522120
+84522190
+84522910
+84522921
+84522922
+84522923
+84522924
+84522925
+84522929
+84522990
+84523000
+84529020
+84529081
+84529089
+84529091
+84529092
+84529093
+84529094
+84529099
+84531010
+84531090
+84532000
+84538000
+84539000
+84541000
+84542010
+84542090
+84543010
+84543020
+84543090
+84549010
+84549090
+84551000
+84552110
+84552190
+84552210
+84552290
+84553010
+84553020
+84553090
+84559000
+84561111
+84561119
+84561190
+84561211
+84561219
+84561290
+84562010
+84562090
+84563011
+84563019
+84563090
+84564000
+84565000
+84569000
+84571000
+84572010
+84572090
+84573010
+84573090
+84581110
+84581191
+84581199
+84581910
+84581990
+84589100
+84589900
+84591000
+84592110
+84592191
+84592199
+84592900
+84593100
+84593900
+84594100
+84594900
+84595100
+84595900
+84596100
+84596900
+84597000
+84601200
+84601900
+84602200
+84602300
+84602400
+84602900
+84603100
+84603900
+84604011
+84604019
+84604091
+84604099
+84609011
+84609012
+84609019
+84609090
+84612010
+84612090
+84613010
+84613090
+84614010
+84614091
+84614099
+84615010
+84615020
+84615090
+84619010
+84619090
+84621100
+84621900
+84622200
+84622300
+84622400
+84622500
+84622600
+84622900
+84623200
+84623300
+84623900
+84624200
+84624900
+84625100
+84625900
+84626100
+84626200
+84626300
+84626900
+84629000
+84631010
+84631090
+84632010
+84632091
+84632099
+84633000
+84639010
+84639090
+84641000
+84642010
+84642021
+84642029
+84642090
+84649011
+84649019
+84649090
+84651000
+84652000
+84659110
+84659120
+84659190
+84659211
+84659219
+84659290
+84659310
+84659390
+84659400
+84659511
+84659512
+84659591
+84659592
+84659600
+84659900
+84661000
+84662010
+84662090
+84663000
+84669100
+84669200
+84669311
+84669319
+84669320
+84669330
+84669340
+84669350
+84669360
+84669410
+84669420
+84669490
+84671110
+84671190
+84671900
+84672100
+84672200
+84672910
+84672991
+84672992
+84672993
+84672999
+84678100
+84678900
+84679100
+84679200
+84679900
+84681000
+84682000
+84688010
+84688090
+84689010
+84689020
+84689090
+84701000
+84702100
+84702900
+84703000
+84705010
+84705090
+84709010
+84709090
+84713011
+84713012
+84713019
+84713090
+84714100
+84714900
+84715010
+84715020
+84715030
+84715040
+84715090
+84716052
+84716053
+84716054
+84716059
+84716061
+84716062
+84716080
+84716090
+84717010
+84717020
+84717030
+84717040
+84717090
+84718000
+84719011
+84719012
+84719013
+84719014
+84719019
+84719090
+84721000
+84723010
+84723020
+84723030
+84723090
+84729010
+84729020
+84729030
+84729040
+84729051
+84729059
+84729091
+84729099
+84732100
+84732910
+84732920
+84732990
+84733011
+84733019
+84733031
+84733032
+84733033
+84733034
+84733039
+84733041
+84733042
+84733049
+84733090
+84734010
+84734070
+84734090
+84735010
+84735040
+84735050
+84735090
+84741000
+84742010
+84742090
+84743100
+84743200
+84743900
+84748010
+84748090
+84749000
+84751000
+84752100
+84752910
+84752990
+84759000
+84762100
+84762900
+84768100
+84768910
+84768990
+84769000
+84771011
+84771019
+84771021
+84771029
+84771091
+84771099
+84772010
+84772090
+84773010
+84773090
+84774010
+84774090
+84775100
+84775911
+84775919
+84775990
+84778010
+84778090
+84779000
+84781010
+84781090
+84789000
+84791010
+84791090
+84792000
+84793000
+84794000
+84795000
+84796000
+84797100
+84797900
+84798110
+84798190
+84798210
+84798290
+84798300
+84798911
+84798912
+84798921
+84798922
+84798931
+84798932
+84798940
+84798991
+84798992
+84798999
+84799010
+84799090
+84801000
+84802000
+84803000
+84804100
+84804910
+84804990
+84805000
+84806000
+84807100
+84807910
+84807990
+84811000
+84812011
+84812019
+84812090
+84813000
+84814000
+84818011
+84818019
+84818021
+84818029
+84818031
+84818039
+84818091
+84818092
+84818093
+84818094
+84818095
+84818096
+84818097
+84818099
+84819010
+84819090
+84821010
+84821090
+84822010
+84822090
+84823000
+84824000
+84825010
+84825090
+84828000
+84829111
+84829119
+84829120
+84829130
+84829190
+84829910
+84829990
+84831011
+84831019
+84831020
+84831030
+84831040
+84831050
+84831090
+84832000
+84833010
+84833021
+84833029
+84833090
+84834010
+84834090
+84835010
+84835090
+84836011
+84836019
+84836090
+84839000
+84841000
+84842000
+84849000
+84851000
+84852000
+84853000
+84858000
+84859000
+84861000
+84862000
+84863000
+84864000
+84869000
+84871000
+84879000
+85011011
+85011019
+85011021
+85011029
+85011030
+85012000
+85013110
+85013120
+85013210
+85013220
+85013310
+85013320
+85013411
+85013419
+85013420
+85014011
+85014019
+85014021
+85014029
+85015110
+85015120
+85015190
+85015210
+85015220
+85015290
+85015310
+85015320
+85015330
+85015390
+85016100
+85016200
+85016300
+85016400
+85017100
+85017210
+85017290
+85018000
+85021110
+85021190
+85021210
+85021290
+85021311
+85021319
+85021390
+85022011
+85022019
+85022090
+85023100
+85023900
+85024010
+85024090
+85030010
+85030090
+85041000
+85042100
+85042200
+85042300
+85043111
+85043119
+85043191
+85043192
+85043193
+85043199
+85043211
+85043219
+85043221
+85043229
+85043300
+85043400
+85044010
+85044021
+85044022
+85044029
+85044030
+85044040
+85044050
+85044060
+85044090
+85045010
+85045090
+85049010
+85049020
+85049030
+85049040
+85049090
+85051100
+85051910
+85051990
+85052010
+85052090
+85059011
+85059019
+85059080
+85059090
+85061011
+85061012
+85061019
+85061020
+85061031
+85061032
+85061039
+85063010
+85063090
+85064010
+85064090
+85065010
+85065090
+85066010
+85066090
+85068010
+85068090
+85069000
+85071010
+85071090
+85072010
+85072090
+85073011
+85073019
+85073090
+85075010
+85075020
+85075090
+85076000
+85078000
+85079010
+85079020
+85079090
+85081100
+85081900
+85086000
+85087000
+85094010
+85094020
+85094030
+85094040
+85094050
+85094090
+85098010
+85098090
+85099000
+85101000
+85102000
+85103000
+85109011
+85109019
+85109020
+85109090
+85111000
+85112010
+85112090
+85113010
+85113020
+85114000
+85115010
+85115090
+85118010
+85118020
+85118030
+85118090
+85119000
+85121000
+85122011
+85122019
+85122021
+85122022
+85122023
+85122029
+85123000
+85124010
+85124020
+85129000
+85131010
+85131090
+85139000
+85141100
+85141900
+85142011
+85142019
+85142020
+85143100
+85143200
+85143900
+85144000
+85149000
+85151100
+85151900
+85152100
+85152900
+85153110
+85153190
+85153900
+85158010
+85158090
+85159000
+85161000
+85162100
+85162900
+85163100
+85163200
+85163300
+85164000
+85165000
+85166000
+85167100
+85167200
+85167910
+85167920
+85167990
+85168010
+85168090
+85169000
+85171100
+85171300
+85171410
+85171431
+85171432
+85171439
+85171441
+85171449
+85171490
+85171830
+85171890
+85176130
+85176141
+85176142
+85176143
+85176149
+85176191
+85176192
+85176199
+85176214
+85176215
+85176221
+85176229
+85176234
+85176239
+85176241
+85176249
+85176251
+85176252
+85176253
+85176254
+85176255
+85176256
+85176259
+85176262
+85176264
+85176265
+85176272
+85176273
+85176277
+85176278
+85176279
+85176291
+85176294
+85176296
+85176299
+85176900
+85177110
+85177120
+85177190
+85177900
+85181010
+85181090
+85182100
+85182200
+85182910
+85182990
+85183000
+85184000
+85185000
+85189010
+85189090
+85192000
+85193000
+85198110
+85198120
+85198190
+85198900
+85211010
+85211081
+85211089
+85211090
+85219000
+85221000
+85229000
+85232110
+85232120
+85232911
+85232919
+85232990
+85234110
+85234190
+85234910
+85234920
+85234990
+85235110
+85235190
+85235210
+85235290
+85235900
+85238000
+85241100
+85241200
+85241900
+85249100
+85249200
+85249900
+85255011
+85255019
+85255021
+85255022
+85255023
+85255024
+85255029
+85256010
+85256020
+85256090
+85258100
+85258200
+85258300
+85258911
+85258912
+85258913
+85258914
+85258919
+85258921
+85258922
+85258929
+85261000
+85269100
+85269200
+85271200
+85271300
+85271900
+85272100
+85272900
+85279100
+85279200
+85279910
+85279990
+85284200
+85284930
+85284990
+85285200
+85285900
+85286200
+85286910
+85286990
+85287111
+85287119
+85287190
+85287200
+85287300
+85291020
+85291090
+85299011
+85299012
+85299019
+85299020
+85299030
+85299040
+85299050
+85299090
+85301010
+85301090
+85308010
+85308090
+85309000
+85311010
+85311090
+85312000
+85318000
+85319000
+85321000
+85322111
+85322119
+85322120
+85322190
+85322200
+85322310
+85322390
+85322410
+85322420
+85322490
+85322510
+85322590
+85322910
+85322990
+85323010
+85323090
+85329000
+85331000
+85332110
+85332120
+85332190
+85332900
+85333110
+85333190
+85333910
+85333990
+85334011
+85334012
+85334013
+85334019
+85334091
+85334092
+85334099
+85339000
+85340011
+85340012
+85340013
+85340019
+85340020
+85340031
+85340032
+85340033
+85340039
+85340040
+85340051
+85340059
+85351000
+85352100
+85352900
+85353013
+85353017
+85353018
+85353019
+85353023
+85353027
+85353028
+85353029
+85354010
+85354090
+85359010
+85359090
+85361000
+85362000
+85363010
+85363090
+85364100
+85364900
+85365010
+85365020
+85365030
+85365090
+85366100
+85366910
+85366990
+85367000
+85369010
+85369020
+85369030
+85369040
+85369050
+85369060
+85369090
+85371011
+85371019
+85371020
+85371030
+85371090
+85372010
+85372090
+85381000
+85389010
+85389020
+85389090
+85391010
+85391090
+85392110
+85392190
+85392200
+85392910
+85392990
+85393111
+85393119
+85393120
+85393131
+85393132
+85393139
+85393210
+85393220
+85393230
+85393911
+85393912
+85393913
+85393919
+85393990
+85394110
+85394190
+85394900
+85395100
+85395200
+85399010
+85399020
+85399090
+85401100
+85401200
+85402011
+85402019
+85402020
+85402090
+85404000
+85406010
+85406090
+85407100
+85407900
+85408100
+85408910
+85408990
+85409110
+85409120
+85409130
+85409140
+85409190
+85409900
+85411011
+85411012
+85411019
+85411021
+85411022
+85411029
+85411031
+85411032
+85411039
+85411091
+85411092
+85411099
+85412110
+85412120
+85412191
+85412199
+85412910
+85412920
+85413011
+85413019
+85413021
+85413029
+85414111
+85414112
+85414121
+85414122
+85414123
+85414124
+85414210
+85414220
+85414290
+85414300
+85414900
+85415100
+85415900
+85416010
+85416090
+85419010
+85419020
+85419090
+85423110
+85423120
+85423190
+85423210
+85423221
+85423229
+85423291
+85423299
+85423311
+85423319
+85423320
+85423390
+85423911
+85423919
+85423920
+85423931
+85423939
+85423991
+85423999
+85429000
+85431000
+85432000
+85433010
+85433090
+85434000
+85437011
+85437012
+85437013
+85437014
+85437015
+85437019
+85437020
+85437031
+85437032
+85437033
+85437034
+85437035
+85437036
+85437039
+85437040
+85437050
+85437091
+85437092
+85437099
+85439010
+85439090
+85441100
+85441911
+85441919
+85441990
+85442000
+85443000
+85444200
+85444900
+85446000
+85447010
+85447020
+85447030
+85447090
+85451100
+85451910
+85451920
+85451990
+85452000
+85459010
+85459020
+85459030
+85459090
+85461000
+85462000
+85469000
+85471000
+85472010
+85472090
+85479000
+85480010
+85480090
+85491100
+85491200
+85491300
+85491400
+85491900
+85492100
+85492900
+85493100
+85493900
+85499100
+85499900
+86011000
+86012000
+86021000
+86029000
+86031000
+86039000
+86040010
+86040090
+86050010
+86050090
+86061000
+86063000
+86069100
+86069200
+86069900
+86071110
+86071120
+86071200
+86071911
+86071919
+86071990
+86072100
+86072900
+86073000
+86079100
+86079900
+86080011
+86080012
+86080090
+86090000
+87011000
+87012100
+87012200
+87012300
+87012400
+87012900
+87013000
+87019100
+87019200
+87019300
+87019410
+87019490
+87019510
+87019590
+87021000
+87022000
+87023000
+87024010
+87024090
+87029000
+87031000
+87032100
+87032210
+87032290
+87032310
+87032390
+87032410
+87032490
+87033110
+87033190
+87033210
+87033290
+87033310
+87033390
+87034000
+87035000
+87036000
+87037000
+87038000
+87039000
+87041010
+87041090
+87042110
+87042120
+87042130
+87042190
+87042210
+87042220
+87042230
+87042290
+87042310
+87042320
+87042330
+87042340
+87042390
+87043110
+87043120
+87043130
+87043190
+87043210
+87043220
+87043230
+87043290
+87044100
+87044200
+87044300
+87045100
+87045200
+87046000
+87049000
+87051020
+87051030
+87051090
+87052000
+87053000
+87054000
+87059010
+87059090
+87060010
+87060020
+87060090
+87071000
+87079010
+87079090
+87081000
+87082100
+87082200
+87082911
+87082912
+87082913
+87082914
+87082919
+87082991
+87082992
+87082993
+87082994
+87082995
+87082999
+87083011
+87083019
+87083090
+87084011
+87084019
+87084080
+87084090
+87085011
+87085012
+87085019
+87085080
+87085091
+87085099
+87087010
+87087090
+87088000
+87089100
+87089200
+87089300
+87089411
+87089412
+87089413
+87089481
+87089482
+87089483
+87089490
+87089510
+87089521
+87089522
+87089529
+87089910
+87089990
+87091100
+87091900
+87099000
+87100000
+87111000
+87112010
+87112020
+87112090
+87113000
+87114000
+87115000
+87116000
+87119000
+87120010
+87120090
+87131000
+87139000
+87141000
+87142000
+87149100
+87149200
+87149311
+87149319
+87149320
+87149410
+87149490
+87149500
+87149611
+87149612
+87149619
+87149690
+87149910
+87149920
+87149990
+87150000
+87161000
+87162000
+87163100
+87163900
+87164000
+87168000
+87169010
+87169090
+88010000
+88021100
+88021210
+88021290
+88022010
+88022021
+88022022
+88022090
+88023010
+88023021
+88023029
+88023031
+88023039
+88023090
+88024010
+88024090
+88026000
+88040000
+88051000
+88052100
+88052900
+88061000
+88062100
+88062200
+88062300
+88062400
+88062900
+88069100
+88069200
+88069300
+88069400
+88069900
+88071000
+88072000
+88073000
+88079000
+89011000
+89012000
+89013000
+89019000
+89020010
+89020090
+89031100
+89031200
+89031900
+89032100
+89032200
+89032300
+89033100
+89033200
+89033300
+89039300
+89039900
+89040000
+89051000
+89052000
+89059000
+89061000
+89069000
+89071000
+89079000
+89080000
+90011011
+90011019
+90011020
+90012000
+90013000
+90014000
+90015000
+90019010
+90019090
+90021111
+90021119
+90021120
+90021190
+90021900
+90022010
+90022090
+90029010
+90029090
+90031100
+90031910
+90031990
+90039010
+90039090
+90041000
+90049010
+90049020
+90049090
+90051000
+90058000
+90059010
+90059090
+90063000
+90064000
+90065310
+90065320
+90065930
+90065940
+90065951
+90065959
+90066100
+90066900
+90069110
+90069190
+90069900
+90071000
+90072020
+90072090
+90079100
+90079200
+90085000
+90089000
+90101010
+90101020
+90101090
+90105010
+90105020
+90105090
+90106000
+90109010
+90109090
+90111000
+90112010
+90112020
+90112030
+90118010
+90118090
+90119010
+90119090
+90121010
+90121090
+90129010
+90129090
+90131010
+90131090
+90132000
+90138000
+90139000
+90141000
+90142010
+90142020
+90142030
+90142090
+90148010
+90148090
+90149000
+90151000
+90152010
+90152090
+90153000
+90154000
+90158010
+90158090
+90159010
+90159090
+90160010
+90160090
+90171010
+90171090
+90172000
+90173010
+90173020
+90173090
+90178010
+90178090
+90179010
+90179090
+90181100
+90181210
+90181290
+90181300
+90181410
+90181420
+90181490
+90181910
+90181920
+90181980
+90181990
+90182010
+90182020
+90182090
+90183111
+90183119
+90183190
+90183211
+90183212
+90183213
+90183219
+90183220
+90183910
+90183921
+90183922
+90183923
+90183925
+90183926
+90183929
+90183930
+90183991
+90183999
+90184100
+90184911
+90184912
+90184919
+90184920
+90184940
+90184991
+90184999
+90185010
+90185090
+90189010
+90189021
+90189029
+90189031
+90189039
+90189040
+90189050
+90189061
+90189069
+90189091
+90189093
+90189094
+90189095
+90189096
+90189097
+90189099
+90191000
+90192010
+90192020
+90192030
+90192040
+90192090
+90200010
+90200090
+90211010
+90211020
+90211091
+90211099
+90212110
+90212190
+90212900
+90213110
+90213120
+90213190
+90213911
+90213919
+90213920
+90213930
+90213940
+90213980
+90213991
+90213999
+90214000
+90215000
+90219011
+90219012
+90219013
+90219019
+90219080
+90219091
+90219092
+90219099
+90221200
+90221311
+90221319
+90221390
+90221411
+90221412
+90221413
+90221419
+90221490
+90221910
+90221991
+90221999
+90222110
+90222120
+90222190
+90222910
+90222990
+90223000
+90229010
+90229020
+90229080
+90229091
+90229099
+90230000
+90241010
+90241020
+90241090
+90248011
+90248019
+90248021
+90248029
+90248090
+90249000
+90251111
+90251119
+90251191
+90251199
+90251910
+90251990
+90258000
+90259010
+90259090
+90261011
+90261019
+90261021
+90261029
+90262010
+90262090
+90268000
+90269010
+90269020
+90269090
+90271000
+90272011
+90272012
+90272019
+90272021
+90272029
+90273011
+90273019
+90273020
+90275010
+90275020
+90275030
+90275040
+90275050
+90275090
+90278100
+90278911
+90278912
+90278913
+90278914
+90278920
+90278991
+90278999
+90279010
+90279091
+90279093
+90279099
+90281011
+90281019
+90281090
+90282010
+90282020
+90283011
+90283019
+90283021
+90283029
+90283031
+90283039
+90283090
+90289010
+90289090
+90291010
+90291090
+90292010
+90292020
+90299010
+90299090
+90301010
+90301090
+90302010
+90302021
+90302022
+90302029
+90302030
+90303100
+90303200
+90303311
+90303319
+90303321
+90303329
+90303390
+90303910
+90303990
+90304010
+90304020
+90304030
+90304090
+90308210
+90308290
+90308410
+90308420
+90308490
+90308910
+90308920
+90308930
+90308940
+90308990
+90309010
+90309090
+90311000
+90312010
+90312090
+90314100
+90314910
+90314920
+90314990
+90318011
+90318012
+90318020
+90318030
+90318040
+90318050
+90318060
+90318091
+90318099
+90319010
+90319090
+90321010
+90321090
+90322000
+90328100
+90328911
+90328919
+90328921
+90328922
+90328923
+90328924
+90328925
+90328929
+90328930
+90328981
+90328982
+90328983
+90328984
+90328989
+90328990
+90329010
+90329091
+90329099
+90330000
+91011100
+91011900
+91012100
+91012900
+91019100
+91019900
+91021110
+91021190
+91021210
+91021220
+91021290
+91021900
+91022100
+91022900
+91029100
+91029900
+91031000
+91039000
+91040000
+91051100
+91051900
+91052100
+91052900
+91059100
+91059900
+91061000
+91069000
+91070010
+91070090
+91081110
+91081190
+91081200
+91081900
+91082000
+91089000
+91091000
+91099000
+91101110
+91101190
+91101200
+91101900
+91109000
+91111000
+91112010
+91112090
+91118000
+91119010
+91119090
+91122000
+91129000
+91131000
+91132000
+91139000
+91143000
+91144000
+91149000
+92011000
+92012000
+92019000
+92021000
+92029000
+92051000
+92059000
+92060000
+92071010
+92071090
+92079010
+92079090
+92081000
+92089000
+92093000
+92099100
+92099200
+92099400
+92099900
+93011000
+93012000
+93019000
+93020000
+93031000
+93032000
+93033000
+93039010
+93039090
+93040010
+93040090
+93051000
+93052000
+93059100
+93059900
+93062110
+93062120
+93062130
+93062190
+93062900
+93063000
+93069010
+93069020
+93069090
+93070000
+94011010
+94011090
+94012000
+94013100
+94013900
+94014100
+94014900
+94015200
+94015300
+94015900
+94016100
+94016900
+94017100
+94017900
+94018000
+94019100
+94019900
+94021000
+94029010
+94029020
+94029090
+94031000
+94032010
+94032090
+94033000
+94034000
+94035000
+94036000
+94037000
+94038200
+94038300
+94038900
+94039100
+94039900
+94041000
+94042100
+94042900
+94043000
+94044000
+94049000
+94051110
+94051190
+94051910
+94051990
+94052100
+94052900
+94053100
+94053900
+94054100
+94054200
+94054900
+94055000
+94056100
+94056900
+94059100
+94059200
+94059900
+94061010
+94061090
+94062000
+94069010
+94069020
+94069090
+95030010
+95030021
+95030022
+95030029
+95030031
+95030039
+95030040
+95030050
+95030060
+95030070
+95030080
+95030091
+95030097
+95030098
+95030099
+95042000
+95043000
+95044000
+95045000
+95049010
+95049090
+95051000
+95059000
+95061100
+95061200
+95061900
+95062100
+95062900
+95063100
+95063200
+95063900
+95064000
+95065100
+95065900
+95066100
+95066200
+95066900
+95067000
+95069100
+95069900
+95071000
+95072000
+95073000
+95079000
+95081000
+95082110
+95082120
+95082190
+95082210
+95082290
+95082300
+95082400
+95082500
+95082600
+95082900
+95083000
+95084000
+96011000
+96019000
+96020010
+96020020
+96020090
+96031000
+96032100
+96032900
+96033000
+96034010
+96034090
+96035000
+96039000
+96040000
+96050000
+96061000
+96062100
+96062200
+96062900
+96063000
+96071100
+96071900
+96072000
+96081000
+96082000
+96083000
+96084000
+96085000
+96086000
+96089100
+96089981
+96089989
+96089990
+96091000
+96092000
+96099000
+96100000
+96110000
+96121000
+96122000
+96131000
+96132000
+96138000
+96139000
+96140000
+96151100
+96151900
+96159000
+96161000
+96162000
+96170010
+96170020
+96180000
+96190000
+96200000
+97012100
+97012200
+97012900
+97019100
+97019200
+97019900
+97021000
+97029000
+97031000
+97039000
+97040000
+97051000
+97052100
+97052200
+97052900
+97053100
+97053900
+97061000
+97069000
diff --git a/docs/runs/rtc_copy_write_e2e.json b/docs/runs/rtc_copy_write_e2e.json
new file mode 100644
index 0000000..446d924
--- /dev/null
+++ b/docs/runs/rtc_copy_write_e2e.json
@@ -0,0 +1,230 @@
+{
+ "database": "scratch_rtc_e2e/TESTESOFICIAIS_RTC_COPY.FDB (gbak restore of TESTESOFICIAIS)",
+ "real_database_writes": 0,
+ "real_database_write_attempts": 0,
+ "copy_original_crt": [
+ "1"
+ ],
+ "copy_crt_for_experiment": "3",
+ "copy_rtc_param": 1,
+ "coverage_before": {
+ "total": 521,
+ "complete": 0,
+ "blocked": 521,
+ "unclassified": 0,
+ "coverage_percent": 0.0
+ },
+ "resolution_before": {
+ "total": 521,
+ "valid_existing": 0,
+ "ready_to_apply": 280,
+ "ambiguous": 215,
+ "insufficient": 26,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-A1": 41,
+ "RTC-A3": 10,
+ "RTC-R2": 26,
+ "RTC-R4": 203,
+ "RTC-R3": 77,
+ "RTC-A2": 164
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "stale_decision_run": {
+ "write_attempts": 280,
+ "write_successes": 0,
+ "aborted_reasons": {
+ "RTC_NO_LONGER_ENABLED": 280
+ }
+ },
+ "first_run": {
+ "mode": "AUTO_APPLY",
+ "ready_total": 280,
+ "write_attempts": 280,
+ "write_successes": 280,
+ "aborted_reasons": {},
+ "audit_sample": [
+ {
+ "outcome": "APPLIED",
+ "product_code": "000023",
+ "field": "CCLASSTRIB",
+ "old_value": null,
+ "new_value": "000001",
+ "cst_ibscbs": "000",
+ "rule_id": "RTC-R4",
+ "confidence_type": "EXCLUSION_OF_ALL_SPECIAL_REGIMES",
+ "evidence": {
+ "inputs_used": {
+ "ncm": "16025000",
+ "crt": "3",
+ "rtc_enabled": true
+ },
+ "evidence": [
+ {
+ "annex_hits": 0,
+ "chapter": "16"
+ }
+ ],
+ "reason": "NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER"
+ },
+ "official_source_version": {
+ "cclasstrib_table": "2026-06-22",
+ "cclasstrib_sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "lc214_sha256": "5c7d59b3c49e5b7c066c2ad28bedf32791193a676ec1a163bec14bea5fa2f680"
+ },
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "timestamp": "2026-09-25T00:07:47+00:00",
+ "job_id": 424242,
+ "rowcount": 1,
+ "verified_after": true
+ },
+ {
+ "outcome": "APPLIED",
+ "product_code": "000024",
+ "field": "CCLASSTRIB",
+ "old_value": null,
+ "new_value": "200034",
+ "cst_ibscbs": "200",
+ "rule_id": "RTC-R3",
+ "confidence_type": "ANNEX_TEXT_MATCH",
+ "evidence": {
+ "inputs_used": {
+ "ncm": "19022000",
+ "crt": "3",
+ "rtc_enabled": true
+ },
+ "evidence": [
+ {
+ "annex": "VII",
+ "item": 9,
+ "prefix": "19022000",
+ "clean": true,
+ "revoked": false,
+ "text": "Massas alimentícias dos códigos 1902.20.00 e 1902.30.00 da NCM/SH"
+ }
+ ],
+ "reason": "ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS"
+ },
+ "official_source_version": {
+ "cclasstrib_table": "2026-06-22",
+ "cclasstrib_sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "lc214_sha256": "5c7d59b3c49e5b7c066c2ad28bedf32791193a676ec1a163bec14bea5fa2f680"
+ },
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "timestamp": "2026-09-25T00:07:47+00:00",
+ "job_id": 424242,
+ "rowcount": 1,
+ "verified_after": true
+ },
+ {
+ "outcome": "APPLIED",
+ "product_code": "000027",
+ "field": "CCLASSTRIB",
+ "old_value": null,
+ "new_value": "200034",
+ "cst_ibscbs": "200",
+ "rule_id": "RTC-R3",
+ "confidence_type": "ANNEX_TEXT_MATCH",
+ "evidence": {
+ "inputs_used": {
+ "ncm": "19022000",
+ "crt": "3",
+ "rtc_enabled": true
+ },
+ "evidence": [
+ {
+ "annex": "VII",
+ "item": 9,
+ "prefix": "19022000",
+ "clean": true,
+ "revoked": false,
+ "text": "Massas alimentícias dos códigos 1902.20.00 e 1902.30.00 da NCM/SH"
+ }
+ ],
+ "reason": "ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS"
+ },
+ "official_source_version": {
+ "cclasstrib_table": "2026-06-22",
+ "cclasstrib_sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "lc214_sha256": "5c7d59b3c49e5b7c066c2ad28bedf32791193a676ec1a163bec14bea5fa2f680"
+ },
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "timestamp": "2026-09-25T00:07:47+00:00",
+ "job_id": 424242,
+ "rowcount": 1,
+ "verified_after": true
+ }
+ ]
+ },
+ "rows_changed": 280,
+ "columns_changed": [
+ "CCLASSTRIB"
+ ],
+ "fk_orphans": 0,
+ "cst_orphans": 0,
+ "written_by_class": {
+ "000001": 203,
+ "200014": 2,
+ "200034": 75
+ },
+ "catalog_rows_unchanged": 145,
+ "coverage_after": {
+ "total": 521,
+ "complete": 279,
+ "blocked": 242,
+ "unclassified": 0,
+ "coverage_percent": 53.55
+ },
+ "resolution_after": {
+ "total": 521,
+ "valid_existing": 280,
+ "ready_to_apply": 0,
+ "ambiguous": 215,
+ "insufficient": 26,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-A1": 41,
+ "RTC-A3": 10,
+ "RTC-R2": 26,
+ "RTC-R4": 203,
+ "RTC-R3": 77,
+ "RTC-A2": 164
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "second_run": {
+ "ready_total": 0,
+ "write_attempts": 0,
+ "write_successes": 0
+ },
+ "IDEMPOTENT": true,
+ "ONLY_CCLASSTRIB_CHANGED": true,
+ "PASS": true
+}
\ No newline at end of file
diff --git a/docs/runs/rtc_official_catalog.txt b/docs/runs/rtc_official_catalog.txt
new file mode 100644
index 0000000..886eb4a
--- /dev/null
+++ b/docs/runs/rtc_official_catalog.txt
@@ -0,0 +1,164 @@
+000001|000|Padrão|0|0|2026-01-01T00:00:00|||Situações tributadas integralmente pelo IBS e CBS.
+000002|000|Padrão|0|0|2026-01-01T00:00:00||90111|Exploração de via
+000003|000|Padrão|0|0|2026-01-01T00:00:00|||Regime automotivo - projetos incentivados (art. 311)
+000004|000|Padrão|0|0|2026-01-01T00:00:00|||Regime automotivo - projetos incentivados (art. 312)
+000005|000|Padrão|0|0|2026-01-01T00:00:00|||Operação com EAC destinado à mistura com gasolina A, mas com saída do biocombustível com destinação diversa
+010001|010|Uniforme setorial|0|0|2026-01-01T00:00:00|||Operações do FGTS não realizadas pela Caixa Econômica Federal
+010002|010|Uniforme setorial|0|0|2026-01-01T00:00:00|||Operações do serviço financeiro
+011001|011|Uniforme nacional (referência)|60|60|2026-01-01T00:00:00|||Planos de assistência funerária.
+011002|011|Uniforme nacional (referência)|60|60|2026-01-01T00:00:00|||Planos de assistência à saúde
+011003|011|Uniforme nacional (referência)|60|60|2026-01-01T00:00:00||92401|Intermediação de planos de assistência à saúde
+011004|011|Uniforme nacional (referência)|0|0|2026-01-01T00:00:00|||Concursos e prognósticos
+011005|011|Uniforme nacional (referência)|30|30|2026-01-01T00:00:00|||Planos de assistência à saúde de animais domésticos
+200001|200|Padrão|100|100|2026-01-01T00:00:00|||Serviços de transporte de bens até as zonas de processamento de exportação e bens exportados a partir das zonas de processamento de exportação
+200002|200|Padrão|100|100|2026-01-01T00:00:00|||Fornecimento ou importação para produtor rural não contribuinte ou TAC
+200003|200|Padrão|100|100|2026-01-01T00:00:00||1|Vendas de produtos destinados à alimentação humana (Anexo I)
+200004|200|Padrão|100|100|2026-01-01T00:00:00||12|Fornecimento de dispositivos médicos (Anexo XII)
+200005|200|Padrão|100|100|2026-01-01T00:00:00||4|Fornecimento de dispositivos médicos para órgãos da administração pública e entidades de saúde imunes (Anexo IV)
+200006|200|Padrão|100|100|2026-01-01T00:00:00|||Situação de emergência de saúde pública reconhecida pelo Poder público
+200007|200|Padrão|100|100|2026-01-01T00:00:00||13|Fornecimento dos dispositivos de acessibilidade próprios para pessoas com deficiência (Anexo XIII)
+200008|200|Padrão|100|100|2026-01-01T00:00:00||5|Fornecimento dos dispositivos de acessibilidade próprios para pessoas com deficiência adquiridos por órgãos da administração pública (Anexo V)
+200009|200|Padrão|100|100|2026-01-01T00:00:00|||Fornecimento dos medicamentos registrados na Anvisa
+200010|200|Padrão|100|100|2026-01-01T00:00:00|||Fornecimento dos medicamentos registrados na Anvisa, adquiridos por órgãos da administração pública
+200011|200|Padrão|100|100|2026-01-01T00:00:00||6|Fornecimento das composições para nutrição enteral e parenteral quando adquiridas por órgãos da administração pública (Anexo VI)
+200012|200|Padrão|100|100|2026-01-01T00:00:00|||Situação de emergência de saúde pública reconhecida pelo Poder público
+200013|200|Padrão|100|100|2026-01-01T00:00:00||91471|Fornecimento de tampões higiênicos, absorventes higiênicos internos ou externos
+200014|200|Padrão|100|100|2026-01-01T00:00:00||15|Fornecimento dos produtos hortícolas, frutas e ovos (Anexo XV)
+200015|200|Padrão|100|100|2026-01-01T00:00:00|||Venda de automóveis de passageiros de fabricação nacional adquiridos por motoristas profissionais ou pessoas com deficiência
+200016|200|Padrão|100|100|2026-01-01T00:00:00||91561|Prestação de serviços de pesquisa e desenvolvimento por Instituição Científica, Tecnológica e de Inovação (ICT)
+200017|200|Padrão|100|100|2026-01-01T00:00:00|||Operações relacionadas ao FGTS
+200018|200|Padrão|100|100|2026-01-01T00:00:00|||Operações de resseguro e retrocessão
+200019|200|Padrão|100|100|2026-01-01T00:00:00|||Importador dos serviços financeiros contribuinte
+200020|200|Padrão|100|100|2026-01-01T00:00:00|||Operação praticada por sociedades cooperativas optantes por regime específico do IBS e CBS
+200021|200|Padrão|100|100|2026-01-01T00:00:00|||Serviços de transporte público coletivo de passageiros ferroviário e hidroviário
+200022|200|Padrão|100|100|2026-01-01T00:00:00|||Operação originada fora da ZFM que destine bem material industrializado a contribuinte estabelecido na ZFM
+200023|200|Padrão|100|100|2026-01-01T00:00:00|||Operação realizada por indústria incentivada que destine bem material intermediário para outra indústria incentivada na ZFM
+200024|200|Padrão|100|100|2026-01-01T00:00:00|||Operação originada fora das Áreas de Livre Comércio destinadas a contribuinte estabelecido nas Áreas de Livre Comércio
+200025|200|Padrão|60|100|2026-01-01T00:00:00||93081|Fornecimento dos serviços de educação relacionados ao Programa Universidade para Todos (Prouni)
+200026|200|Padrão|80|80|2026-01-01T00:00:00||91581|Locação de imóveis localizados nas zonas reabilitadas
+200027|200|Padrão|70|70|2026-01-01T00:00:00||92611|Operações de locação, cessão onerosa e arrendamento de bens imóveis
+200028|200|Padrão|60|60|2026-01-01T00:00:00||2|Fornecimento dos serviços de educação (Anexo II)
+200029|200|Padrão|60|60|2026-01-01T00:00:00||3|Fornecimento dos serviços de saúde humana (Anexo III)
+200030|200|Padrão|60|60|2026-01-01T00:00:00||4|Venda dos dispositivos médicos (Anexo IV)
+200031|200|Padrão|60|60|2026-01-01T00:00:00||5|Fornecimento dos dispositivos de acessibilidade próprios para pessoas com deficiência (Anexo V)
+200032|200|Padrão|60|60|2026-01-01T00:00:00|||Fornecimento dos medicamentos registrados na Anvisa ou produzidos por farmácias de manipulação, ressalvados os medicamentos sujeitos à alíquota zero
+200033|200|Padrão|60|60|2026-01-01T00:00:00||6|Fornecimento das composições para nutrição enteral e parenteral (Anexo VI)
+200034|200|Padrão|60|60|2026-01-01T00:00:00||7|Fornecimento dos alimentos destinados ao consumo humano (Anexo VII)
+200035|200|Padrão|60|60|2026-01-01T00:00:00||8|Fornecimento dos produtos de higiene pessoal e limpeza (Anexo VIII)
+200036|200|Padrão|60|60|2026-01-01T00:00:00|||Fornecimento de produtos agropecuários, aquícolas, pesqueiros, florestais e extrativistas vegetais in natura
+200037|200|Padrão|60|60|2026-01-01T00:00:00|||Fornecimento de serviços ambientais de conservação ou recuperação da vegetação nativa
+200038|200|Padrão|60|60|2026-01-01T00:00:00||9|Fornecimento dos insumos agropecuários e aquícolas (Anexo IX)
+200039|200|Padrão|60|60|2026-01-01T00:00:00||10|Fornecimento dos bens e serviços relacionados com produções nacionais artísticas, culturais, de eventos, jornalísticas e audiovisuais (Anexo X)
+200040|200|Padrão|60|60|2026-01-01T00:00:00|||Fornecimento de serviços de comunicação institucional à administração pública
+200041|200|Padrão|60|60|2026-01-01T00:00:00||91411|Fornecimento de serviço de educação desportiva (art. 141. I)
+200042|200|Padrão|60|60|2026-01-01T00:00:00|||Fornecimento de serviço de gestão e exploração do desporto (art. 141. II)
+200043|200|Padrão|60|60|2026-01-01T00:00:00||11|Fornecimento à administração pública dos serviços e dos bens relativos à soberania (Anexo XI)
+200044|200|Padrão|60|60|2026-01-01T00:00:00||11|Operações e prestações de serviços de segurança da informação e segurança cibernética desenvolvidos por sociedade que tenha sócio brasileiro (Anexo XI)
+200045|200|Padrão|60|60|2026-01-01T00:00:00|||Operações relacionadas a projetos de reabilitação urbana de zonas históricas e de áreas críticas de recuperação e reconversão urbanística
+200046|200|Padrão|50|50|2026-01-01T00:00:00|||Operações com bens imóveis
+200047|200|Padrão|40|40|2026-01-01T00:00:00|||Bares e Restaurantes
+200048|200|Padrão|40|40|2026-01-01T00:00:00||92811|Hotelaria, Parques de Diversão e Parques Temáticos
+200049|200|Padrão|40|40|2026-01-01T00:00:00|||Transporte coletivo de passageiros rodoviário, ferroviário e hidroviário
+200050|200|Padrão|40|40|2026-01-01T00:00:00|||Serviços de transporte aéreo regional coletivo de passageiros ou de carga
+200051|200|Padrão|40|40|2026-01-01T00:00:00|||Agências de Turismo
+200052|200|Padrão|30|30|2026-01-01T00:00:00||91271|Prestação de serviços de profissões intelectuais
+200053|200|Padrão|100|100|2026-01-01T00:00:00|||Fornecimento de medicamentos registrados na Anvisa, quando classificados como soros ou vacinas
+200054|200|Padrão|100|100|2026-01-01T00:00:00|||Fornecimento de bem material pela cooperativa de produção agropecuária a associado não sujeito ao regime regular do IBS e da CBS
+220001|220|Fixa|0|0|2026-01-01T00:00:00|2026-01-01T00:00:00||Incorporação imobiliária submetida ao regime especial de tributação
+220002|220|Fixa|0|0|2026-01-01T00:00:00|2026-01-01T00:00:00||Incorporação imobiliária submetida ao regime especial de tributação
+220003|220|Fixa|0|0|2026-01-01T00:00:00|2026-01-01T00:00:00||Alienação de imóvel decorrente de parcelamento do solo
+221001|221|Fixa|0|0|2026-01-01T00:00:00||94871|Locação, cessão onerosa ou arrendamento de bem imóvel com alíquota sobre a receita bruta
+221002|221|Fixa|0|0|2026-01-01T00:00:00|||Incorporação imobiliária submetida ao regime especial de tributação
+221003|221|Fixa|0|0|2026-01-01T00:00:00|||Incorporação imobiliária submetida ao regime especial de tributação
+221004|221|Fixa|0|0|2026-01-01T00:00:00|||Alienação de imóvel decorrente de parcelamento do solo
+222001|222|Padrão|0|0|2026-01-01T00:00:00|||Transporte internacional de passageiros, caso os trechos de ida e volta sejam vendidos em conjunto
+400001|400|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento de serviços de transporte público coletivo de passageiros rodoviário e metroviário
+400002|400|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento de serviços de transporte público coletivo de passageiros rodoviário e metroviário com medição por quilômetro rodado
+410001|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento de bonificações quando constem no documento fiscal e que não dependam de evento posterior
+410002|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Transferências entre estabelecimentos pertencentes ao mesmo contribuinte
+410003|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Doações sem contraprestação em benefício do doador
+410004|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Exportações de bens e serviços
+410005|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimentos realizados pela União, pelos Estados, pelo Distrito Federal e pelos Municípios
+410006|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimentos realizados por entidades religiosas e templos de qualquer culto
+410007|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimentos realizados por partidos políticos, entidades sindicais e instituições de educação e de assistência social
+410008|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimentos de livros, jornais, periódicos e do papel destinado a sua impressão
+410009|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimentos de fonogramas e videofonogramas musicais produzidos no Brasil
+410010|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimentos de serviço de comunicação nas modalidades de radiodifusão sonora e de sons e imagens de recepção livre e gratuita
+410011|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimentos de ouro, quando definido em lei como ativo financeiro ou instrumento cambial
+410012|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento de condomínio edilício não optante pelo regime regular
+410013|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Exportações de combustíveis
+410014|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento de produtor rural não contribuinte
+410015|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento por transportador autônomo não contribuinte
+410016|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento ou aquisição de resíduos sólidos
+410017|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Aquisição de bem móvel com crédito presumido sob condição de revenda realizada
+410018|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Operações relacionadas aos fundos garantidores e executores de políticas públicas
+410019|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Exclusão da gorjeta na base de cálculo no fornecimento de alimentação
+410020|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Exclusão do valor de intermediação na base de cálculo no fornecimento de alimentação
+410021|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Contribuição de que trata o art. 149-A da Constituição Federal
+410022|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Consolidação da propriedade do bem pelo credor
+410023|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Alienação de bens móveis ou imóveis que tenham sido objeto de garantia em que o prestador da garantia não seja contribuinte
+410024|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Consolidação da propriedade do bem pelo grupo de consórcio
+410025|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Alienação de bem que tenha sido objeto de garantia em que o prestador da garantia não seja contribuinte
+410026|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Doação com anulação de crédito
+410027|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Exportação de serviço ou de bem imaterial
+410028|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Operações com bens imóveis realizadas por pessoas físicas não consideradas contribuintes
+410029|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Operações acobertadas somente pelo ICMS
+410030|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Estorno de crédito por perecimento, deteriorização, roubo, furto ou extravio.
+410031|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento em período anterior ao início de vigência de incidências de CBS e IBS
+410032|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Tributos incidentes na operação que não integram a base de cálculo do IBS e da CBS
+410033|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Operações de Fundos de Investimento Imobiliário (FII) e Fundos de Investimento nas Cadeias Produtivas do Agronegócio (Fiagro)
+410034|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Operações de fundos de investimento
+410035|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Fornecimento realizado por nanoempreendedor
+410036|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Descontos incondicionais
+410037|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Importação os bens materiais sem incidência de IBS e CBS
+410999|410|Sem alíquota|0|0|2026-01-01T00:00:00|||Operações não onerosas sem previsão de tributação, não especificadas anteriormente
+510001|510|Sem alíquota|0|0|2026-01-01T00:00:00||90281|Operações, sujeitas a diferimento, com energia elétrica, relativas à importação, geração, comercialização, distribuição e transmissão
+515001|515|Padrão|60|60|2026-01-01T00:00:00||9|Operações, sujeitas a diferimento, com insumos agropecuários e aquícolas (Anexo IX)
+550001|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Exportações de bens materiais
+550002|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regime de Trânsito
+550003|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regimes de Depósito (art. 85)
+550004|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regimes de Depósito (art. 87)
+550005|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regimes de Depósito (art. 87, Parágrafo único)
+550006|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regimes de Permanência Temporária
+550007|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regimes de Aperfeiçoamento
+550008|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Importação de bens para o Regime de Repetro-Temporário
+550009|550|Sem alíquota|0|0|2026-01-01T00:00:00|||GNL-Temporário
+550010|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Repetro-Permanente
+550011|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Repetro-Industrialização
+550012|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Repetro-Nacional
+550013|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Repetro-Entreposto
+550014|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Zona de Processamento de Exportação
+550015|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regime Tributário para Incentivo à Modernização e à Ampliação da Estrutura Portuária
+550016|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regime Especial de Incentivos para o Desenvolvimento da Infraestrutura
+550017|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regime Tributário para Incentivo à Atividade Naval - Renaval (Art. 107, I)
+550018|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Desoneração da aquisição de bens de capital
+550019|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Importação de bem material por indústria incentivada para utilização na ZFM
+550020|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Áreas de livre comércio
+550021|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Industrialização destinada a exportações
+550022|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regime Especial de Incentivos para a Produção de Hidrogênio de Baixa Emissão de Carbono (Rehidro)
+550023|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Operações com hidrocarbonetos líquidos derivados de petróleo não combustíveis ou de gás natural, inclusive nafta
+550024|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regime Tributário para Incentivo à Atividade Naval - Renaval (Art. 107, II)
+550025|550|Sem alíquota|0|0|2026-01-01T00:00:00|||Regime Tributário para Incentivo à Atividade Naval - Renaval (Art. 107, III)
+620001|620|Uniforme setorial|0|0|2026-01-01T00:00:00||91721|Tributação monofásica sobre combustíveis
+620002|620|Uniforme setorial|0|0|2026-01-01T00:00:00||91722|Tributação monofásica com responsabilidade pela retenção sobre combustíveis
+620003|620|Uniforme setorial|0|0|2026-01-01T00:00:00||91723|Tributação monofásica com responsabilidade de retenção de tributos por terceiros
+620004|620|Uniforme setorial|0|0|2026-01-01T00:00:00||91724|Tributação monofásica sobre mistura de EAC com gasolina A em percentual superior ao obrigatório
+620005|620|Uniforme setorial|0|0|2026-01-01T00:00:00||91725|Tributação monofásica sobre mistura de EAC com gasolina A em percentual inferior ao obrigatório
+620006|620|Uniforme setorial|0|0|2026-01-01T00:00:00||91726|Tributação monofásica sobre combustíveis cobrada anteriormente
+620007|620|Sem alíquota|0|0|2026-01-01T00:00:00|||Perecimento, deteriorização, roubo, furto ou extravio no regime monofásico
+800001|800|Sem alíquota|0|0|2026-01-01T00:00:00|||Fusão, cisão ou incorporação
+800002|800|Sem alíquota|0|0|2026-01-01T00:00:00|||Transferência de crédito do associado, inclusive as cooperativas singulares
+810001|810|Sem alíquota|0|0|2026-01-01T00:00:00|||Crédito presumido de IBS sobre o valor apurado nos fornecimentos a partir da ZFM
+811001|811|Sem alíquota|0|0|2026-01-01T00:00:00|||Anulação de Crédito por Saídas Imunes/Isentas
+811002|811|Sem alíquota|0|0|2026-01-01T00:00:00|||Débitos de notas fiscais não processadas na apuração
+811003|811|Sem alíquota|0|0|2026-01-01T00:00:00|||Desenquadramento do Simples Nacional
+820001|820|Sem alíquota|0|0|2026-01-01T00:00:00||92341|Documento com informações de fornecimento de serviços de planos de assistência à saúde elencados no art. 234 da Lei Complementar nº214, de 2025
+820002|820|Sem alíquota|0|0|2026-01-01T00:00:00||92361|Documento com informações de fornecimento de serviços de planos de assistência funerária
+820003|820|Sem alíquota|0|0|2026-01-01T00:00:00||92431|Documento com informações de fornecimento de serviços de planos de assistência à saúde de animais domésticos
+820004|820|Sem alíquota|0|0|2026-01-01T00:00:00|||Documento com informações de prestação de serviços de consursos de prognósticos
+820005|820|Sem alíquota|0|0|2026-01-01T00:00:00|||Documento com informações de alienação de bens imóveis
+820006|820|Sem alíquota|0|0|2026-01-01T00:00:00||90111|Documento com informações de fornecimento de serviços de exploração de via
+820007|820|Sem alíquota|0|0|2026-01-01T00:00:00||91811|Documento com informações de fornecimento de serviços financeiros
+820008|820|Sem alíquota|0|0|2026-01-01T00:00:00|||Documento com informações de fornecimento de serviço continuado, mas com tributação realizada em fatura anterior
+820009|820|Sem alíquota|0|0|2026-01-01T00:00:00|||Cobrança relativa a fornecimentos declarados em outro documento
+830001|830|Sem alíquota|0|0|2026-01-01T00:00:00|||Documento com exclusão da BC da CBS e do IBS de energia elétrica fornecida pela distribuidora à UC
diff --git a/docs/runs/rtc_resolution_audit_sample.csv b/docs/runs/rtc_resolution_audit_sample.csv
new file mode 100644
index 0000000..6ac3e32
--- /dev/null
+++ b/docs/runs/rtc_resolution_audit_sample.csv
@@ -0,0 +1,101 @@
+database,product,ncm,current_cclasstrib,proposed_cclasstrib,status,rule_id,reason,confidence_type,scenario
+TESTESOFICIAIS,000004,07069000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000005,07069000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000006,07069000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000008,07069000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000009,07069000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000010,07069000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000011,07069000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000013,07069000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000015,07133321,,,AMBIGUOUS,RTC-A3,SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000017,03061790,,,AMBIGUOUS,RTC-A1,ANNEX_VII_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000018,02071100,,,AMBIGUOUS,RTC-A1,ANNEX_I_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000019,07133321,,,AMBIGUOUS,RTC-A3,SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000021,07089000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000022,07089000,,,AMBIGUOUS,RTC-A1,ANNEX_XV_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000023,16025000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000024,19022000,,200034,RESOLVED_WITH_EXPLICIT_RULE,RTC-R3,ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS,ANNEX_TEXT_MATCH,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000025,04061010,,,AMBIGUOUS,RTC-A1,ANNEX_I_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000026,03055100,,,AMBIGUOUS,RTC-A3,SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000027,19022000,,200034,RESOLVED_WITH_EXPLICIT_RULE,RTC-R3,ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS,ANNEX_TEXT_MATCH,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+TESTESOFICIAIS,000028,19022000,,200034,RESOLVED_WITH_EXPLICIT_RULE,RTC-R3,ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS,ANNEX_TEXT_MATCH,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000001,72142000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000002,72142000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000003,72142000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000004,72142000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000005,72142000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000006,72142000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000007,72142000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000008,25232910,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000009,25232910,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000010,25232910,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000011,68118200,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000012,72142000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000013,68101100,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000014,68101100,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000015,40139000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000016,40139000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000017,30045020,,,AMBIGUOUS,RTC-A1,ANNEX_IX_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000018,56075090,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000019,56075090,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+CONSTRUCAO,000020,56075090,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000002,19022000,,200034,RESOLVED_WITH_EXPLICIT_RULE,RTC-R3,ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS,ANNEX_TEXT_MATCH,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000003,61046300,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000006,61046300,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000008,61046200,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000011,61091000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000013,61051000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000014,61051000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000016,61051000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000017,62111100,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000018,62111100,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000019,62034200,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000020,42021220,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000022,42021900,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000023,65040090,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000024,61091000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000025,61091000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000026,61061000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000027,62064000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000028,62046200,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+MMMODAS,000029,62034300,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000001,21050090,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000004,17041000,,,AMBIGUOUS,RTC-A1,ANNEX_X_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000005,17041000,,,AMBIGUOUS,RTC-A1,ANNEX_X_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000006,17041000,,,AMBIGUOUS,RTC-A1,ANNEX_X_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000007,17041000,,,AMBIGUOUS,RTC-A1,ANNEX_X_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000008,17041000,,,AMBIGUOUS,RTC-A1,ANNEX_X_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000009,17041000,,,AMBIGUOUS,RTC-A1,ANNEX_X_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000010,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000011,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000012,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000013,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000014,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000015,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000016,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000017,21069090,,,AMBIGUOUS,RTC-A2,LISTED_IN_MORE_THAN_ONE_ANNEX,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000018,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000019,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000020,21069090,,,AMBIGUOUS,RTC-A2,LISTED_IN_MORE_THAN_ONE_ANNEX,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000021,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+RINCAO,000022,18063210,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000008,33059000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000009,21039021,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000014,19059010,,200034,RESOLVED_WITH_EXPLICIT_RULE,RTC-R3,ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS,ANNEX_TEXT_MATCH,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000015,95051000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000016,21032010,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000017,95030099,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000018,38089999,,,AMBIGUOUS,RTC-A1,ANNEX_IX_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000019,38089999,,,AMBIGUOUS,RTC-A1,ANNEX_IX_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000020,38089999,,,AMBIGUOUS,RTC-A1,ANNEX_IX_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000021,95051000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000022,22021000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000023,19053100,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000024,82041100,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000025,04089900,,,AMBIGUOUS,RTC-A3,SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000026,15171000,,200003,RESOLVED_WITH_EXPLICIT_RULE,RTC-R3,ANNEX_I_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS,ANNEX_TEXT_MATCH,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000027,82054000,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000028,04090000,,200034,RESOLVED_WITH_EXPLICIT_RULE,RTC-R3,ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS,ANNEX_TEXT_MATCH,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000029,19053100,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000030,04022120,,,AMBIGUOUS,RTC-A1,ANNEX_I_NEEDS_OPERATION_OR_CONDITION,NONE,"WHATIF_NORMAL_ON (regime normal, RTC on)"
+UNIAO,000031,19053100,,000001,RESOLVED_WITH_EXPLICIT_RULE,RTC-R4,NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER,EXCLUSION_OF_ALL_SPECIAL_REGIMES,"WHATIF_NORMAL_ON (regime normal, RTC on)"
diff --git a/docs/runs/rtc_resolution_dryrun.json b/docs/runs/rtc_resolution_dryrun.json
new file mode 100644
index 0000000..3137d97
--- /dev/null
+++ b/docs/runs/rtc_resolution_dryrun.json
@@ -0,0 +1,941 @@
+{
+ "mode": "READ_ONLY_DRY_RUN",
+ "FIREBIRD_WRITES": 0,
+ "WRITE_ATTEMPTS": 0,
+ "WRITE_SUCCESSES": 0,
+ "databases": {
+ "TESTESOFICIAIS": {
+ "crt": "1",
+ "total_products": 521,
+ "passes": {
+ "AS_FOUND": {
+ "crt": "1",
+ "rtc_enabled": true,
+ "products": 521,
+ "resolution_summary": {
+ "total": 521,
+ "valid_existing": 0,
+ "ready_to_apply": 0,
+ "ambiguous": 0,
+ "insufficient": 521,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R1": 521
+ },
+ "by_reason": {
+ "SIMPLES_ORIENTATION_PENDING_OFFICIAL_NT": 521
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "INSUFFICIENT_EVIDENCE": 521
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING_UNRESOLVED": 521
+ },
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "1",
+ "rtc_source": "PARAMETROS.USAR_REFORMA_TRIBUTARIA",
+ "rtc_observed_at": "2026-09-25T00:11:38+00:00",
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_RTC_ON": {
+ "crt": "1",
+ "rtc_enabled": true,
+ "products": 521,
+ "resolution_summary": {
+ "total": 521,
+ "valid_existing": 0,
+ "ready_to_apply": 0,
+ "ambiguous": 0,
+ "insufficient": 521,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R1": 521
+ },
+ "by_reason": {
+ "SIMPLES_ORIENTATION_PENDING_OFFICIAL_NT": 521
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "INSUFFICIENT_EVIDENCE": 521
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING_UNRESOLVED": 521
+ },
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "1",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:38+00:00",
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_NORMAL_ON": {
+ "crt": "3",
+ "rtc_enabled": true,
+ "products": 521,
+ "resolution_summary": {
+ "total": 521,
+ "valid_existing": 0,
+ "ready_to_apply": 280,
+ "ambiguous": 215,
+ "insufficient": 26,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-A1": 41,
+ "RTC-A3": 10,
+ "RTC-R2": 26,
+ "RTC-R4": 203,
+ "RTC-R3": 77,
+ "RTC-A2": 164
+ },
+ "by_reason": {
+ "ANNEX_XV_NEEDS_OPERATION_OR_CONDITION": 14,
+ "SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD": 10,
+ "NO_VALID_NCM": 26,
+ "ANNEX_VII_NEEDS_OPERATION_OR_CONDITION": 10,
+ "ANNEX_I_NEEDS_OPERATION_OR_CONDITION": 14,
+ "NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER": 203,
+ "ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 75,
+ "ANNEX_XV_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 2,
+ "LISTED_IN_MORE_THAN_ONE_ANNEX": 164,
+ "ANNEX_V_NEEDS_OPERATION_OR_CONDITION": 3
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "AMBIGUOUS": 215,
+ "INSUFFICIENT_EVIDENCE": 26,
+ "RESOLVED_WITH_EXPLICIT_RULE": 280
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_AMBIGUOUS": 215,
+ "RTC_RULE_EVIDENCE_MISSING": 26,
+ "CCLASSTRIB_MISSING": 280
+ },
+ "AUTO_APPLY_CANDIDATES": 280,
+ "context": {
+ "rtc_param": "1",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:38+00:00",
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ }
+ }
+ },
+ "CONSTRUCAO": {
+ "crt": "1",
+ "total_products": 3712,
+ "passes": {
+ "AS_FOUND": {
+ "crt": "1",
+ "rtc_enabled": true,
+ "products": 3712,
+ "resolution_summary": {
+ "total": 3712,
+ "valid_existing": 0,
+ "ready_to_apply": 0,
+ "ambiguous": 0,
+ "insufficient": 3712,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R1": 3712
+ },
+ "by_reason": {
+ "SIMPLES_ORIENTATION_PENDING_OFFICIAL_NT": 3712
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "INSUFFICIENT_EVIDENCE": 3712
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING_UNRESOLVED": 3712
+ },
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "1",
+ "rtc_source": "PARAMETROS.USAR_REFORMA_TRIBUTARIA",
+ "rtc_observed_at": "2026-09-25T00:11:39+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_RTC_ON": {
+ "crt": "1",
+ "rtc_enabled": true,
+ "products": 3712,
+ "resolution_summary": {
+ "total": 3712,
+ "valid_existing": 0,
+ "ready_to_apply": 0,
+ "ambiguous": 0,
+ "insufficient": 3712,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R1": 3712
+ },
+ "by_reason": {
+ "SIMPLES_ORIENTATION_PENDING_OFFICIAL_NT": 3712
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "INSUFFICIENT_EVIDENCE": 3712
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING_UNRESOLVED": 3712
+ },
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "1",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:39+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_NORMAL_ON": {
+ "crt": "3",
+ "rtc_enabled": true,
+ "products": 3712,
+ "resolution_summary": {
+ "total": 3712,
+ "valid_existing": 0,
+ "ready_to_apply": 2725,
+ "ambiguous": 973,
+ "insufficient": 14,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R4": 2725,
+ "RTC-A1": 255,
+ "RTC-R2": 14,
+ "RTC-A3": 682,
+ "RTC-A2": 36
+ },
+ "by_reason": {
+ "NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER": 2725,
+ "ANNEX_IX_NEEDS_OPERATION_OR_CONDITION": 63,
+ "NO_VALID_NCM": 14,
+ "SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD": 682,
+ "ANNEX_IV_NEEDS_OPERATION_OR_CONDITION": 179,
+ "LISTED_IN_MORE_THAN_ONE_ANNEX": 36,
+ "ANNEX_XI_NEEDS_OPERATION_OR_CONDITION": 8,
+ "ANNEX_V_NEEDS_OPERATION_OR_CONDITION": 1,
+ "ANNEX_XIII_NEEDS_OPERATION_OR_CONDITION": 4
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "RESOLVED_WITH_EXPLICIT_RULE": 2725,
+ "AMBIGUOUS": 973,
+ "INSUFFICIENT_EVIDENCE": 14
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING": 2725,
+ "CCLASSTRIB_AMBIGUOUS": 973,
+ "RTC_RULE_EVIDENCE_MISSING": 14
+ },
+ "AUTO_APPLY_CANDIDATES": 2725,
+ "context": {
+ "rtc_param": "1",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:40+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ }
+ }
+ },
+ "MMMODAS": {
+ "crt": "1",
+ "total_products": 20997,
+ "passes": {
+ "AS_FOUND": {
+ "crt": "1",
+ "rtc_enabled": false,
+ "products": 20996,
+ "resolution_summary": null,
+ "by_status": {
+ "NOT_EVALUATED": 20996
+ },
+ "rtc_blocker_types": {},
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "PARAMETROS.USAR_REFORMA_TRIBUTARIA",
+ "rtc_observed_at": "2026-09-25T00:11:43+00:00",
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "official_catalog": null,
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_RTC_ON": {
+ "crt": "1",
+ "rtc_enabled": true,
+ "products": 20996,
+ "resolution_summary": {
+ "total": 20996,
+ "valid_existing": 0,
+ "ready_to_apply": 0,
+ "ambiguous": 0,
+ "insufficient": 20996,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R1": 20996
+ },
+ "by_reason": {
+ "SIMPLES_ORIENTATION_PENDING_OFFICIAL_NT": 20996
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "INSUFFICIENT_EVIDENCE": 20996
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING_UNRESOLVED": 20996
+ },
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:44+00:00",
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_NORMAL_ON": {
+ "crt": "3",
+ "rtc_enabled": true,
+ "products": 20996,
+ "resolution_summary": {
+ "total": 20996,
+ "valid_existing": 0,
+ "ready_to_apply": 20831,
+ "ambiguous": 49,
+ "insufficient": 116,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R3": 1,
+ "RTC-R4": 20830,
+ "RTC-R2": 116,
+ "RTC-A3": 48,
+ "RTC-A1": 1
+ },
+ "by_reason": {
+ "ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 1,
+ "NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER": 20830,
+ "NO_VALID_NCM": 116,
+ "SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD": 48,
+ "ANNEX_XV_NEEDS_OPERATION_OR_CONDITION": 1
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "RESOLVED_WITH_EXPLICIT_RULE": 20831,
+ "INSUFFICIENT_EVIDENCE": 116,
+ "AMBIGUOUS": 49
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING": 20831,
+ "RTC_RULE_EVIDENCE_MISSING": 116,
+ "CCLASSTRIB_AMBIGUOUS": 49
+ },
+ "AUTO_APPLY_CANDIDATES": 20831,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:49+00:00",
+ "local_catalog_hash": "1da77aec27fbde88488d1edf562f3af315ab2b5d06efb2e0b2f1ed606585d459",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ }
+ }
+ },
+ "RINCAO": {
+ "crt": "3",
+ "total_products": 894,
+ "passes": {
+ "AS_FOUND": {
+ "crt": "3",
+ "rtc_enabled": false,
+ "products": 894,
+ "resolution_summary": null,
+ "by_status": {
+ "NOT_EVALUATED": 894
+ },
+ "rtc_blocker_types": {},
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "PARAMETROS.USAR_REFORMA_TRIBUTARIA",
+ "rtc_observed_at": "2026-09-25T00:11:50+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": null,
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_RTC_ON": {
+ "crt": "3",
+ "rtc_enabled": true,
+ "products": 894,
+ "resolution_summary": {
+ "total": 894,
+ "valid_existing": 0,
+ "ready_to_apply": 530,
+ "ambiguous": 364,
+ "insufficient": 0,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R4": 467,
+ "RTC-A1": 129,
+ "RTC-A2": 234,
+ "RTC-R3": 63,
+ "RTC-A3": 1
+ },
+ "by_reason": {
+ "NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER": 467,
+ "ANNEX_X_NEEDS_OPERATION_OR_CONDITION": 109,
+ "LISTED_IN_MORE_THAN_ONE_ANNEX": 234,
+ "ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 59,
+ "ANNEX_I_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 2,
+ "ANNEX_XV_NEEDS_OPERATION_OR_CONDITION": 16,
+ "SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD": 1,
+ "ANNEX_XV_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 2,
+ "ANNEX_I_NEEDS_OPERATION_OR_CONDITION": 3,
+ "ANNEX_VII_NEEDS_OPERATION_OR_CONDITION": 1
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "RESOLVED_WITH_EXPLICIT_RULE": 530,
+ "AMBIGUOUS": 364
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING": 530,
+ "CCLASSTRIB_AMBIGUOUS": 364
+ },
+ "AUTO_APPLY_CANDIDATES": 530,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:50+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_NORMAL_ON": {
+ "crt": "3",
+ "rtc_enabled": true,
+ "products": 894,
+ "resolution_summary": {
+ "total": 894,
+ "valid_existing": 0,
+ "ready_to_apply": 530,
+ "ambiguous": 364,
+ "insufficient": 0,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R4": 467,
+ "RTC-A1": 129,
+ "RTC-A2": 234,
+ "RTC-R3": 63,
+ "RTC-A3": 1
+ },
+ "by_reason": {
+ "NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER": 467,
+ "ANNEX_X_NEEDS_OPERATION_OR_CONDITION": 109,
+ "LISTED_IN_MORE_THAN_ONE_ANNEX": 234,
+ "ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 59,
+ "ANNEX_I_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 2,
+ "ANNEX_XV_NEEDS_OPERATION_OR_CONDITION": 16,
+ "SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD": 1,
+ "ANNEX_XV_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 2,
+ "ANNEX_I_NEEDS_OPERATION_OR_CONDITION": 3,
+ "ANNEX_VII_NEEDS_OPERATION_OR_CONDITION": 1
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "RESOLVED_WITH_EXPLICIT_RULE": 530,
+ "AMBIGUOUS": 364
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING": 530,
+ "CCLASSTRIB_AMBIGUOUS": 364
+ },
+ "AUTO_APPLY_CANDIDATES": 530,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:50+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ }
+ }
+ },
+ "UNIAO": {
+ "crt": "1",
+ "total_products": 8942,
+ "passes": {
+ "AS_FOUND": {
+ "crt": "1",
+ "rtc_enabled": false,
+ "products": 8942,
+ "resolution_summary": null,
+ "by_status": {
+ "NOT_EVALUATED": 8942
+ },
+ "rtc_blocker_types": {},
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "PARAMETROS.USAR_REFORMA_TRIBUTARIA",
+ "rtc_observed_at": "2026-09-25T00:11:52+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": null,
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_RTC_ON": {
+ "crt": "1",
+ "rtc_enabled": true,
+ "products": 8942,
+ "resolution_summary": {
+ "total": 8942,
+ "valid_existing": 0,
+ "ready_to_apply": 0,
+ "ambiguous": 0,
+ "insufficient": 8942,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R1": 8942
+ },
+ "by_reason": {
+ "SIMPLES_ORIENTATION_PENDING_OFFICIAL_NT": 8942
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "INSUFFICIENT_EVIDENCE": 8942
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING_UNRESOLVED": 8942
+ },
+ "AUTO_APPLY_CANDIDATES": 0,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:52+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ },
+ "WHATIF_NORMAL_ON": {
+ "crt": "3",
+ "rtc_enabled": true,
+ "products": 8942,
+ "resolution_summary": {
+ "total": 8942,
+ "valid_existing": 0,
+ "ready_to_apply": 7419,
+ "ambiguous": 1432,
+ "insufficient": 91,
+ "conflicts": 0,
+ "official_mismatch": 0,
+ "not_applicable": 0,
+ "other_blocked": 0,
+ "by_rule": {
+ "RTC-R4": 6430,
+ "RTC-R3": 989,
+ "RTC-A1": 821,
+ "RTC-A3": 296,
+ "RTC-R2": 91,
+ "RTC-A2": 315
+ },
+ "by_reason": {
+ "NCM_IN_NO_ANNEX_AND_NO_NATURE_BASED_CHAPTER": 6430,
+ "ANNEX_VII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 113,
+ "ANNEX_IX_NEEDS_OPERATION_OR_CONDITION": 174,
+ "SPECIAL_REGIME_DEPENDS_ON_NATURE_OR_OPERATION_OF_THE_GOOD": 296,
+ "ANNEX_I_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 262,
+ "ANNEX_I_NEEDS_OPERATION_OR_CONDITION": 196,
+ "ANNEX_VII_NEEDS_OPERATION_OR_CONDITION": 193,
+ "NO_VALID_NCM": 91,
+ "LISTED_IN_MORE_THAN_ONE_ANNEX": 315,
+ "ANNEX_VIII_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 580,
+ "ANNEX_X_NEEDS_OPERATION_OR_CONDITION": 22,
+ "ANNEX_IV_NEEDS_OPERATION_OR_CONDITION": 156,
+ "ANNEX_XV_CLEAN_ITEM_UNIQUE_DEFAULT_CLASS": 34,
+ "ANNEX_II_NEEDS_OPERATION_OR_CONDITION": 11,
+ "ANNEX_XV_NEEDS_OPERATION_OR_CONDITION": 42,
+ "ANNEX_V_NEEDS_OPERATION_OR_CONDITION": 12,
+ "ANNEX_XI_NEEDS_OPERATION_OR_CONDITION": 12,
+ "ANNEX_VI_NEEDS_OPERATION_OR_CONDITION": 3
+ },
+ "catalog_compatibility": {
+ "compatibility": "MATERIAL_MISMATCH",
+ "counts": {
+ "MATCH": 131,
+ "LOCAL_ONLY": 0,
+ "OFFICIAL_ONLY": 19,
+ "MISMATCH": 11,
+ "EXPIRED": 3
+ },
+ "expired_present_locally": 3
+ }
+ },
+ "by_status": {
+ "RESOLVED_WITH_EXPLICIT_RULE": 7419,
+ "AMBIGUOUS": 1432,
+ "INSUFFICIENT_EVIDENCE": 91
+ },
+ "rtc_blocker_types": {
+ "CCLASSTRIB_MISSING": 7419,
+ "CCLASSTRIB_AMBIGUOUS": 1432,
+ "RTC_RULE_EVIDENCE_MISSING": 91
+ },
+ "AUTO_APPLY_CANDIDATES": 7419,
+ "context": {
+ "rtc_param": "0",
+ "rtc_source": "SIMULATION",
+ "rtc_observed_at": "2026-09-25T00:11:54+00:00",
+ "local_catalog_hash": "be8c5899fff3e236c6c77bbb887087c0a2db048aeff763a5823676c7b478a151",
+ "official_catalog": {
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "file": "cClassTrib 2026-06-22.xlsx"
+ },
+ "catalog_integrity": {
+ "classes": 145,
+ "cst": 18,
+ "orphan_classes": 0,
+ "bad_class_format": 0,
+ "bad_cst_format": 0,
+ "duplicates": 0,
+ "valid": true
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/docs/sources/RTC_REFERENCE_MANIFEST_V1.json b/docs/sources/RTC_REFERENCE_MANIFEST_V1.json
new file mode 100644
index 0000000..c57cab8
--- /dev/null
+++ b/docs/sources/RTC_REFERENCE_MANIFEST_V1.json
@@ -0,0 +1,79 @@
+{
+ "official_catalog": {
+ "file": "cClassTrib 2026-06-22.xlsx",
+ "sha256": "1448cb63a41bdb67ea30b4e11f4dc200d9568542c6b9335b6cff87a4fd664654",
+ "publication": "2026-06-22",
+ "source": "Portal Nacional da NF-e (cClassTrib)",
+ "parser": "rtc-cclasstrib-xlsx-v1"
+ },
+ "official_classes": 164,
+ "lc214": {
+ "document": "Lei Complementar 214/2025 compiled (through LC 227/2026)",
+ "url": "https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp214.htm",
+ "sha256": "5c7d59b3c49e5b7c066c2ad28bedf32791193a676ec1a163bec14bea5fa2f680",
+ "accessed_at": "2026-09-24",
+ "fetched_via": "Internet Archive copy of the official URL"
+ },
+ "annex_items_total_and_clean": {
+ "I": [
+ 26,
+ 16
+ ],
+ "II": [
+ 9,
+ 6
+ ],
+ "III": [
+ 30,
+ 28
+ ],
+ "IV": [
+ 105,
+ 98
+ ],
+ "V": [
+ 3,
+ 3
+ ],
+ "VI": [
+ 81,
+ 80
+ ],
+ "VII": [
+ 17,
+ 7
+ ],
+ "VIII": [
+ 7,
+ 7
+ ],
+ "IX": [
+ 35,
+ 18
+ ],
+ "X": [
+ 57,
+ 47
+ ],
+ "XI": [
+ 2,
+ 0
+ ],
+ "XII": [
+ 17,
+ 12
+ ],
+ "XIII": [
+ 6,
+ 4
+ ],
+ "XIV": [
+ 82,
+ 82
+ ],
+ "XV": [
+ 6,
+ 4
+ ]
+ }
+}
\ No newline at end of file
diff --git a/docs/unified_fiscal_completeness.md b/docs/unified_fiscal_completeness.md
index 9db7afb..f9afd70 100644
--- a/docs/unified_fiscal_completeness.md
+++ b/docs/unified_fiscal_completeness.md
@@ -51,3 +51,10 @@ Somente leitura. `FIREBIRD_WRITES=0`: a avaliação abre uma conexão `READ COMM
| TESTESOFICIAIS | 1 | **ligada** | 521 | 0 | 521 (RTC) | 0 | 0% | 94,82% (494/521) |
Bancos além do piloto: medida só da parte fiscal (`--fiscal-only`, sem decisão do Hub). TESTESOFICIAIS: com a decisão do Hub (antes 495/521 = 95,01%). Bloqueios PIS/COFINS: TESTESOFICIAIS 1 produto (incidência SUBST.TRIBUTÁRIA com CST 01), RINCAO 1 produto (`049`/`000`), demais 0. Produtos com warning (não bloqueante): RINCAO 78 (`4`→`04`, não canônico), UNIAO 2 (CST `000`/`060` inválido, ignorado por ser Simples), TESTESOFICIAIS 1 (não canônico). Aplicabilidade: Simples ⇒ `NOT_APPLICABLE`; RINCAO ⇒ `OPTIONAL` (894); TESTESOFICIAIS 519 `NOT_APPLICABLE` + 2 `REQUIRED`.
+
+
+## RTC no motor único (cClassTrib) — atualização
+- **RTC ligada** ⇒ o Agent avalia cada produto com o resolver determinístico (`docs/cclasstrib_resolution.md`) e transforma o resultado em UM blocker de causa raiz por produto (mesma fila, categoria `RTC`): `CCLASSTRIB_MISSING` (pronto para preencher), `CCLASSTRIB_MISSING_UNRESOLVED`, `CCLASSTRIB_AMBIGUOUS`, `RTC_RULE_EVIDENCE_MISSING`, `RTC_LOCAL_CATALOG_OUTDATED`, `CCLASSTRIB_OFFICIAL_MISMATCH`, `CCLASSTRIB_CONFLICT`. **RTC desligada** ⇒ nenhuma avaliação, nenhum blocker, nada no painel além de "Desativada".
+- Cobertura continua UMA: produto só é completo quando o `CCLASSTRIB` é válido (ou seja, depois de preenchido pelo operador ou pelo auto-apply autorizado). Produtos "prontos para preenchimento" contam como bloqueados até a escrita.
+- O painel explica o 0%: "Reforma Tributária ativa — cClassTrib pendente em N produtos" + resumo Total / válidos / prontos / ambíguos-bloqueados.
+- Preenchimento automático: `docs/rtc_auto_apply.md` (desligado por padrão; três chaves; somente `CCLASSTRIB`; auditado).
diff --git a/release/RELEASE_MANIFEST.json b/release/RELEASE_MANIFEST.json
index 52c9e21..b584d7a 100644
--- a/release/RELEASE_MANIFEST.json
+++ b/release/RELEASE_MANIFEST.json
@@ -1,14 +1,14 @@
{
"artifact": "RELEASE_MANIFEST",
- "GTI_FISCAL_VERSION": "1.1.8",
+ "GTI_FISCAL_VERSION": "1.1.9",
"generated_at": "2026-09-24T14:13:15+00:00",
"hub": {
- "version": "1.1.8",
+ "version": "1.1.9",
"api_compat": "1.0",
"engine_version": "0.3.0",
"decision_version": "mission-04c-ipi-ex-split"
},
- "agent_version": "1.1.8",
+ "agent_version": "1.1.9",
"fiscal_engine": {
"ENGINE_VERSION": "0.3.0",
"DECISION_VERSION": "mission-04c-ipi-ex-split",
@@ -17,10 +17,10 @@
"ICMS_CONTEXT_ENGINE_VERSION": "icms-context-v1"
},
"migrations": {
- "alembic_head_in_repo": "0026_central_processing_control",
- "applied_revision": "0026_central_processing_control",
+ "alembic_head_in_repo": "0027_rtc_auto_apply",
+ "applied_revision": "0027_rtc_auto_apply",
"applied_revision_source": "production Hub 10.0.10.117 (gti-fiscal-hub-fiscal-hub-1), verified 2026-09-24",
- "count": 26
+ "count": 27
},
"datasets_active": [
{
diff --git a/release/VERSION b/release/VERSION
index 18efdb9..512a1fa 100644
--- a/release/VERSION
+++ b/release/VERSION
@@ -1 +1 @@
-1.1.8
+1.1.9
diff --git a/scripts/build_rtc_reference_data.py b/scripts/build_rtc_reference_data.py
new file mode 100644
index 0000000..bdd1599
--- /dev/null
+++ b/scripts/build_rtc_reference_data.py
@@ -0,0 +1,102 @@
+"""Build central/app/rtc_reference_data.py: the OFFICIAL cClassTrib catalog + the LC 214/2025 goods annexes as structured, hash-pinned reference data.
+
+ python scripts/build_rtc_reference_data.py
+
+Inputs (all official, already downloaded/hashed):
+ sources/raw/bootstrap_v1/cClassTrib 2026-06-22.xlsx Portal Nacional NF-e cClassTrib table (parsed with the Hub's own parser)
+ sources_cache/wb_lc214.bin LC 214/2025 compiled (Planalto, through LC 227/2026), extracted to text
+
+Nothing here decides anything: it only turns the published texts into data with provenance. Item texts that carry a condition/exception are
+marked `clean=False` so the resolver never treats them as a deterministic match.
+"""
+import hashlib
+import html
+import json
+import re
+import sys
+from datetime import date
+from pathlib import Path
+from pprint import pformat
+
+ROOT = Path(__file__).resolve().parents[1]
+sys.path.insert(0, str(ROOT))
+from central.app.datasets.bootstrap_v1_extra import parse_rtc_cclasstrib # noqa: E402
+
+XLSX = ROOT / "sources" / "raw" / "bootstrap_v1" / "cClassTrib 2026-06-22.xlsx"
+LC214 = ROOT / "sources_cache" / "wb_lc214.bin"
+ROMAN = {"I": 1, "II": 2, "III": 3, "IV": 4, "V": 5, "VI": 6, "VII": 7, "VIII": 8, "IX": 9, "X": 10, "XI": 11, "XII": 12, "XIII": 13, "XIV": 14, "XV": 15}
+RESTRICTION = re.compile(r"exceto|ressalv|desde que|em conformidade|requisitos|somente|exclusiv|quando|observad|salvo|apenas|conforme|vedad|\ba\)|\bb\)|\bex\b|não", re.I)
+CODE = re.compile(r"\b(\d{2}\.\d{2}(?:\.\d{1,2}){0,2}|\d{4}(?:\.\d{1,2}){1,3})\b")
+
+
+def lc214_text():
+ raw = LC214.read_bytes()
+ text = raw.decode("latin-1", errors="replace")
+ text = re.sub(r"|", "", text, flags=re.S)
+ text = html.unescape(re.sub(r"<[^>]+>", " ", text))
+ return raw, re.sub(r"[ \t\r\f\v]+", " ", text)
+
+
+def parse_annexes(text):
+ heads = [(m.start(), m.group(1)) for m in re.finditer(r"\n[ \xa0]*ANEXO ([IVXL]+)[ \xa0]*\n", text)]
+ blocks, seen = {}, set()
+ for i, (pos, roman) in enumerate(heads):
+ if roman in seen or roman not in ROMAN:
+ continue
+ # the goods annexes I..XV are the first occurrence of each numeral, before the Simples annexes (which repeat I..VII)
+ seen.add(roman)
+ end = heads[i + 1][0] if i + 1 < len(heads) else len(text)
+ blocks[roman] = text[pos:end]
+ out = {}
+ for roman, block in blocks.items():
+ head = " ".join(block[:600].split())
+ items, current, expected = [], None, 1
+ lines = [ln.strip() for ln in block.split("\n")]
+ for idx, ln in enumerate(lines):
+ if ln == str(expected):
+ nxt = next((x for x in lines[idx + 1:idx + 8] if x), "")
+ if nxt and not nxt.isdigit():
+ current = {"item": expected, "text": []}
+ items.append(current)
+ expected += 1
+ continue
+ if current is not None and ln:
+ current["text"].append(ln)
+ parsed = []
+ for it in items:
+ desc = " ".join(" ".join(it["text"]).split())
+ prefixes = sorted({re.sub(r"\D", "", c) for c in CODE.findall(desc)})
+ clean = not RESTRICTION.search(desc) and bool(prefixes)
+ parsed.append({"item": it["item"], "description": desc[:400], "prefixes": prefixes, "clean": clean})
+ out[roman] = {"number": ROMAN[roman], "title": head[:200], "revoked": "Revogado" in head, "items": parsed}
+ return out
+
+
+def main():
+ payload = parse_rtc_cclasstrib(XLSX.read_bytes())
+ official = []
+ for e in payload.entries:
+ ind = e["indicators"]
+ official.append({"code": e["cclasstrib"], "cst": e["cst"], "name": (e["name"] or "")[:160], "tipo_aliquota": e["tipo_aliquota"], "p_red_ibs": e["p_red_ibs"], "p_red_cbs": e["p_red_cbs"],
+ "start": (e["d_ini_vig"] or "")[:10] or None, "end": (e["d_fim_vig"] or "")[:10] or None, "anexo": e.get("anexo"), "ind_nfe": ind.get("indNFe") == "1", "ind_nfce": ind.get("indNFCe") == "1"})
+ raw, text = lc214_text()
+ annexes = parse_annexes(text)
+ counts = {k: (len(v["items"]), sum(1 for i in v["items"] if i["clean"])) for k, v in annexes.items()}
+ module = ROOT / "central" / "app" / "rtc_reference_data.py"
+ catalog_meta = {"file": XLSX.name, "sha256": hashlib.sha256(XLSX.read_bytes()).hexdigest(), "publication": "2026-06-22", "source": "Portal Nacional da NF-e (cClassTrib)", "parser": payload.parser_version}
+ lc_meta = {"document": "Lei Complementar 214/2025 compiled (through LC 227/2026)", "url": "https://www.planalto.gov.br/ccivil_03/leis/lcp/lcp214.htm", "sha256": hashlib.sha256(raw).hexdigest(),
+ "accessed_at": date.today().isoformat(), "fetched_via": "Internet Archive copy of the official URL"}
+ header = '"""GENERATED by scripts/build_rtc_reference_data.py - do not edit. Official cClassTrib catalog and LC 214/2025 goods annexes with provenance."""' + "\n\n"
+ body = "\n\n".join([
+ "OFFICIAL_CATALOG = " + pformat(catalog_meta, width=160),
+ "OFFICIAL_CCLASSTRIB = " + pformat(official, width=220),
+ "LC214_SOURCE = " + pformat(lc_meta, width=160),
+ "LC214_ANNEXES = " + pformat(annexes, width=220),
+ ]) + "\n"
+ module.write_text(header + body, encoding="utf-8")
+ (ROOT / "docs" / "sources" / "RTC_REFERENCE_MANIFEST_V1.json").write_text(json.dumps({"official_catalog": catalog_meta, "official_classes": len(official), "lc214": lc_meta, "annex_items_total_and_clean": counts}, ensure_ascii=False, indent=1), encoding="utf-8")
+ print(len(official), "official classes;", "annex items (total, clean):", counts)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/rtc_copy_write_e2e.py b/scripts/rtc_copy_write_e2e.py
new file mode 100644
index 0000000..df08697
--- /dev/null
+++ b/scripts/rtc_copy_write_e2e.py
@@ -0,0 +1,140 @@
+"""COPY-ONLY write E2E for the RTC auto-apply (C000025.CCLASSTRIB).
+
+ python scripts/rtc_copy_write_e2e.py
+
+Runs ONLY against scratch_rtc_e2e/TESTESOFICIAIS_RTC_COPY.FDB (a gbak restore of TESTESOFICIAIS). It refuses any other path, and refuses every real database.
+Scenario (all through the Agent's own code path `run_agent_service._rtc_auto_apply`):
+ 1. the copy's company is switched to regime normal (C000004.CRT='3'): a disposable experiment, so the rules can act (the real company is Simples => 0 candidates);
+ 2. assess -> candidates; 3. apply with all three gates open; 4. re-read, FK/CST checks, coverage; 5. ONLY CCLASSTRIB changed (whole-table diff);
+ 6. second run: 0 candidates, 0 writes; 7. stale-decision abort (RTC switched off on the copy between decision and write) writes nothing.
+Writes go to the copy and nowhere else.
+"""
+import importlib.util
+import json
+import os
+import sys
+from datetime import date
+from pathlib import Path
+from types import SimpleNamespace
+
+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 fdb # noqa: E402
+import local_completion as lc # noqa: E402
+from central.app.operational_state import classify_product_state, summarize_operational_states # noqa: E402
+from gti_fiscal_agent import firebird_reader, unified_fiscal # noqa: E402
+
+COPY = str((ROOT / "scratch_rtc_e2e" / "TESTESOFICIAIS_RTC_COPY.FDB").resolve())
+NCM_OK = set((ROOT / "docs" / "runs" / "ncm_valid_codes.txt").read_text().split())
+
+
+def guard(path):
+ canon = os.path.normcase(os.path.abspath(path))
+ if canon != os.path.normcase(COPY):
+ raise SystemExit(f"REFUSED: {path} is not the disposable copy")
+ real = {os.path.normcase(os.path.abspath(p)) for p in lc.allowlist().values()}
+ if canon in real or "scratch_rtc_e2e" not in canon:
+ raise SystemExit("REFUSED: real database")
+
+
+def connect(rw):
+ kw = dict(database=COPY, user=os.environ["FB_USER"], password=os.environ["FB_PASSWORD"], fb_library_name=os.environ.get("FIREBIRD_CLIENT_LIBRARY"))
+ if not rw:
+ kw["isolation_level"] = fdb.ISOLATION_LEVEL_READ_COMMITED_RO
+ return fdb.connect(**kw)
+
+
+def load_service():
+ spec = importlib.util.spec_from_file_location("run_agent_service", ROOT / "agent" / "scripts" / "run_agent_service.py")
+ mod = importlib.util.module_from_spec(spec)
+ sys.modules[spec.name] = mod
+ spec.loader.exec_module(mod)
+ return mod
+
+
+def digits(v):
+ return "".join(ch for ch in str(v or "") if ch.isdigit())
+
+
+def snapshot_table(cur, table, key, skip_cols=()):
+ cur.execute(f"SELECT * FROM {table}")
+ cols = [d[0] for d in cur.description]
+ ki = cols.index(key)
+ return cols, {r[ki]: {c: v for c, v in zip(cols, r) if c not in skip_cols} for r in cur.fetchall()}
+
+
+def coverage(env, company, ncm_valid, override=None):
+ conn = firebird_reader._connect(env)
+ try:
+ out = unified_fiscal.assess_from_connection(conn, company, ncm_valid=ncm_valid, rtc_override=override)
+ finally:
+ conn.close()
+ products = firebird_reader.read_products(env)
+ states = [classify_product_state(p, {"status": "EXACT_NCM"}, fiscal=out["findings"].get(str(p["CODIGO"]))) for p in products]
+ s = summarize_operational_states(states)
+ return out, {"total": s["TOTAL_PRODUCTS"], "complete": s["COMPLETE_PRODUCTS"], "blocked": s["SAFE_BLOCKED"], "unclassified": s["UNCLASSIFIED"], "coverage_percent": round(100 * s["COMPLETE_PRODUCTS"] / s["TOTAL_PRODUCTS"], 2)}
+
+
+def main():
+ guard(COPY)
+ service = load_service()
+ env = {"FIREBIRD_DATABASE_PATH": COPY, "FB_USER": os.environ["FB_USER"], "FB_PASSWORD": os.environ["FB_PASSWORD"], "FIREBIRD_CLIENT_LIBRARY": os.environ.get("FIREBIRD_CLIENT_LIBRARY")}
+ report = {"database": "scratch_rtc_e2e/TESTESOFICIAIS_RTC_COPY.FDB (gbak restore of TESTESOFICIAIS)", "real_database_writes": 0, "real_database_write_attempts": 0}
+ # ---- 1. company -> regime normal on the COPY (documented experiment)
+ rw = connect(True); cur = rw.cursor()
+ cur.execute("SELECT DISTINCT TRIM(CRT) FROM C000004"); report["copy_original_crt"] = [r[0] for r in cur.fetchall()]
+ cur.execute("UPDATE C000004 SET CRT = '3'"); rw.commit()
+ cur.execute("SELECT DISTINCT TRIM(CRT) FROM C000004"); company = {"crt": cur.fetchone()[0]}
+ report["copy_crt_for_experiment"] = company["crt"]
+ _, before_c25 = snapshot_table(cur, "C000025", "CODIGO")
+ cur.execute("SELECT USAR_REFORMA_TRIBUTARIA FROM PARAMETROS"); report["copy_rtc_param"] = cur.fetchone()[0]
+ rw.commit(); rw.close()
+ ncm_valid = {str(c).strip(): digits(v["CLASSIFICACAO_FISCAL"]) in NCM_OK for c, v in before_c25.items()}
+ # ---- 2. assess (as found on the copy)
+ out, cov_before = coverage(env, company, ncm_valid)
+ report["coverage_before"] = cov_before
+ report["resolution_before"] = {k: v for k, v in out["context"]["rtc_resolution"].items() if k != "by_reason"}
+ products = firebird_reader.read_products(env)
+ config = SimpleNamespace(firebird_writes=True, rtc_auto_apply_enabled=True, rtc_auto_apply_max_per_job=500, database_path=COPY)
+ job = {"job_id": 424242, "authorizations": {"rtc_auto_apply": True}}
+ # ---- 7 (first, on purpose): stale decision - RTC switched off on the copy between decision and write => nothing is written
+ rw = connect(True); c = rw.cursor(); c.execute("UPDATE PARAMETROS SET USAR_REFORMA_TRIBUTARIA = 0"); rw.commit(); rw.close()
+ stale = service._rtc_auto_apply(env, config, job, products, out, company)
+ report["stale_decision_run"] = {"write_attempts": stale["write_attempts"], "write_successes": stale["write_successes"], "aborted_reasons": stale["aborted_reasons"]}
+ rw = connect(True); c = rw.cursor(); c.execute("UPDATE PARAMETROS SET USAR_REFORMA_TRIBUTARIA = 1"); rw.commit(); rw.close()
+ # ---- 3. apply
+ first = service._rtc_auto_apply(env, config, job, products, out, company)
+ report["first_run"] = {"mode": first["mode"], "ready_total": first["ready_total"], "write_attempts": first["write_attempts"], "write_successes": first["write_successes"], "aborted_reasons": first["aborted_reasons"],
+ "audit_sample": first["applied"][:3]}
+ # ---- 4/5. re-read, FK, whole-table diff
+ ro = connect(False); cur = ro.cursor()
+ cols, after_c25 = snapshot_table(cur, "C000025", "CODIGO")
+ changed = {code: [c for c in cols if before_c25[code][c] != row[c]] for code, row in after_c25.items() if any(before_c25[code][c] != row[c] for c in cols)}
+ report["rows_changed"] = len(changed)
+ report["columns_changed"] = sorted({c for v in changed.values() for c in v})
+ cur.execute("SELECT COUNT(*) FROM C000025 p WHERE p.CCLASSTRIB IS NOT NULL AND NOT EXISTS (SELECT 1 FROM RTC_CCLASSTRIB c WHERE c.CCLASSTRIB = p.CCLASSTRIB)"); report["fk_orphans"] = cur.fetchone()[0]
+ cur.execute("SELECT COUNT(*) FROM C000025 p JOIN RTC_CCLASSTRIB c ON c.CCLASSTRIB = p.CCLASSTRIB WHERE NOT EXISTS (SELECT 1 FROM RTC_CST s WHERE s.CSTIBSCBS = c.CSTIBSCBS)"); report["cst_orphans"] = cur.fetchone()[0]
+ cur.execute("SELECT CCLASSTRIB, COUNT(*) FROM C000025 WHERE CCLASSTRIB IS NOT NULL GROUP BY 1"); report["written_by_class"] = {r[0].strip(): r[1] for r in cur.fetchall()}
+ cur.execute("SELECT COUNT(*) FROM RTC_CCLASSTRIB"); report["catalog_rows_unchanged"] = cur.fetchone()[0]
+ ro.close()
+ out2, cov_after = coverage(env, company, ncm_valid)
+ report["coverage_after"] = cov_after
+ report["resolution_after"] = {k: v for k, v in out2["context"]["rtc_resolution"].items() if k != "by_reason"}
+ # ---- 6. second run
+ products2 = firebird_reader.read_products(env)
+ second = service._rtc_auto_apply(env, config, job, products2, out2, company)
+ report["second_run"] = {"ready_total": second["ready_total"], "write_attempts": second["write_attempts"], "write_successes": second["write_successes"]}
+ report["IDEMPOTENT"] = second["write_attempts"] == 0 and second["write_successes"] == 0
+ report["ONLY_CCLASSTRIB_CHANGED"] = report["columns_changed"] in ([], ["CCLASSTRIB"])
+ report["PASS"] = bool(report["IDEMPOTENT"] and report["ONLY_CCLASSTRIB_CHANGED"] and report["fk_orphans"] == 0 and report["cst_orphans"] == 0 and first["write_successes"] == first["write_attempts"] > 0
+ and report["stale_decision_run"]["write_successes"] == 0 and report["rows_changed"] == first["write_successes"])
+ (ROOT / "docs" / "runs" / "rtc_copy_write_e2e.json").write_text(json.dumps(report, ensure_ascii=False, indent=1, default=str), encoding="utf-8")
+ print(json.dumps({k: report[k] for k in ("copy_original_crt", "copy_rtc_param", "coverage_before", "coverage_after", "first_run", "stale_decision_run", "rows_changed", "columns_changed", "fk_orphans", "cst_orphans", "second_run", "IDEMPOTENT", "ONLY_CCLASSTRIB_CHANGED", "PASS")},
+ ensure_ascii=False, default=str)[:3000])
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/rtc_resolution_dryrun.py b/scripts/rtc_resolution_dryrun.py
new file mode 100644
index 0000000..ac48b74
--- /dev/null
+++ b/scripts/rtc_resolution_dryrun.py
@@ -0,0 +1,79 @@
+"""READ-ONLY dry-run of the deterministic cClassTrib resolver over real Firebird databases. Writes NOTHING to any database.
+
+ python scripts/rtc_resolution_dryrun.py --db TESTESOFICIAIS CONSTRUCAO ... [--out docs/runs/rtc_resolution_dryrun.json]
+
+For each database, three passes over the same read-only snapshot:
+ AS_FOUND the ERP's own RTC switch and the company's real CRT (what the Agent would report today)
+ WHATIF_RTC_ON RTC forced ON (pure evaluator; PARAMETROS is never touched), real CRT
+ WHATIF_NORMAL_ON RTC forced ON and regime normal (CRT 3): what the rules WOULD resolve once an official orientation exists for Simples
+NCM validity = the code exists in the active official NCM table exported from the Hub (docs/runs/ncm_valid_codes.txt).
+"""
+import argparse
+import csv
+import json
+import sys
+from collections import Counter
+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 local_completion as lc # noqa: E402
+from gti_fiscal_agent import firebird_reader, unified_fiscal # noqa: E402
+from unified_coverage_e2e import resolved_crt # noqa: E402
+
+NCM_OK = set((ROOT / "docs" / "runs" / "ncm_valid_codes.txt").read_text().split())
+
+
+def digits(value):
+ return "".join(ch for ch in str(value or "") if ch.isdigit())
+
+
+def one_pass(env, company, override, ncm_valid):
+ conn = firebird_reader._connect(env) # READ COMMITTED READ ONLY
+ try:
+ return unified_fiscal.assess_from_connection(conn, company, rtc_override=override, ncm_valid=ncm_valid)
+ finally:
+ conn.close()
+
+
+def main():
+ ap = argparse.ArgumentParser(); ap.add_argument("--db", nargs="+", required=True); ap.add_argument("--out", default="docs/runs/rtc_resolution_dryrun.json"); ap.add_argument("--sample", type=int, default=100)
+ a = ap.parse_args()
+ report, sample = {}, []
+ for name in a.db:
+ path = lc.allowlist()[name]; env = lc.env_for(path)
+ crt = resolved_crt(name, path)
+ products = firebird_reader.read_products(env)
+ ncm_valid = {str(p["CODIGO"]): digits(p.get("CLASSIFICACAO_FISCAL")) in NCM_OK for p in products}
+ passes = {}
+ for label, override, company in (("AS_FOUND", None, {"crt": crt}), ("WHATIF_RTC_ON", True, {"crt": crt}), ("WHATIF_NORMAL_ON", True, {"crt": "3"})):
+ out = one_pass(env, company, override, ncm_valid)
+ summ = out["context"].get("rtc_resolution")
+ findings = out["findings"]
+ by_status = Counter((f.get("rtc_resolution") or {}).get("status", "NOT_EVALUATED") for f in findings.values())
+ conflicts = Counter(b["type"] for f in findings.values() for b in f["blockers"] if b["category"] == "RTC")
+ passes[label] = {"crt": company["crt"], "rtc_enabled": out["context"]["rtc_enabled"], "products": len(findings), "resolution_summary": summ, "by_status": dict(by_status), "rtc_blocker_types": dict(conflicts),
+ "AUTO_APPLY_CANDIDATES": sum(1 for f in findings.values() if (f.get("rtc_resolution") or {}).get("auto_apply_candidate") and not [b for b in f["blockers"] if b["type"] in ("CCLASSTRIB_CONFLICT",)])}
+ if label == "WHATIF_NORMAL_ON" and len(sample) < a.sample:
+ by_code = {str(p["CODIGO"]): p for p in products}
+ for code, f in findings.items():
+ res = f.get("rtc_resolution")
+ if res and len(sample) < a.sample and (res["auto_apply_candidate"] or res["status"] == "AMBIGUOUS") and (len([s for s in sample if s["database"] == name]) < max(1, a.sample // len(a.db))):
+ p = by_code.get(code, {})
+ sample.append({"database": name, "product": code, "ncm": digits(p.get("CLASSIFICACAO_FISCAL")), "current_cclasstrib": (p.get("CCLASSTRIB") or "").strip() if p.get("CCLASSTRIB") else "", "proposed_cclasstrib": res["resolved_cclasstrib"] or "",
+ "status": res["status"], "rule_id": res["rule_id"], "reason": res["reason"], "confidence_type": res["confidence_type"], "scenario": "WHATIF_NORMAL_ON (regime normal, RTC on)"})
+ passes[label]["context"] = {k: out["context"][k] for k in ("rtc_param", "rtc_source", "rtc_observed_at", "local_catalog_hash", "official_catalog", "catalog_integrity")}
+ report[name] = {"crt": crt, "total_products": len(products), "passes": passes}
+ print(name, "crt", crt, {k: (v["rtc_enabled"], v["by_status"], v["AUTO_APPLY_CANDIDATES"]) for k, v in passes.items()}, flush=True)
+ doc = {"mode": "READ_ONLY_DRY_RUN", "FIREBIRD_WRITES": 0, "WRITE_ATTEMPTS": 0, "WRITE_SUCCESSES": 0, "databases": report}
+ (ROOT / a.out).write_text(json.dumps(doc, ensure_ascii=False, indent=1, default=str), encoding="utf-8")
+ with open(ROOT / "docs" / "runs" / "rtc_resolution_audit_sample.csv", "w", newline="", encoding="utf-8-sig") as fh:
+ w = csv.DictWriter(fh, fieldnames=list(sample[0]) if sample else ["database"]); w.writeheader(); w.writerows(sample)
+ print("sample rows:", len(sample))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/test_release_candidate.py b/tests/test_release_candidate.py
index abebe81..71c0963 100644
--- a/tests/test_release_candidate.py
+++ b/tests/test_release_candidate.py
@@ -14,11 +14,11 @@ sys.path.insert(0, str(ROOT))
def test_versions_are_coherent_across_hub_agent_and_packages():
from central.app.version import GTI_FISCAL_VERSION
v = (ROOT / "release" / "VERSION").read_text(encoding="utf-8").strip()
- assert v == GTI_FISCAL_VERSION == "1.1.8"
+ assert v == GTI_FISCAL_VERSION == "1.1.9"
pep = v.replace("-rc", "rc")
for pp in ("central/pyproject.toml", "agent/pyproject.toml"):
assert f'version = "{pep}"' in (ROOT / pp).read_text(encoding="utf-8")
- assert '"AGENT_VERSION", "1.1.8"' in (ROOT / "agent" / "scripts" / "run_agent_service.py").read_text(encoding="utf-8")
+ assert '"AGENT_VERSION", "1.1.9"' in (ROOT / "agent" / "scripts" / "run_agent_service.py").read_text(encoding="utf-8")
manifest = ROOT / "release" / "RELEASE_MANIFEST.json"
if manifest.exists():
m = json.loads(manifest.read_text(encoding="utf-8"))
diff --git a/tests/test_rtc_copy_write_guard.py b/tests/test_rtc_copy_write_guard.py
new file mode 100644
index 0000000..d753b65
--- /dev/null
+++ b/tests/test_rtc_copy_write_guard.py
@@ -0,0 +1,30 @@
+"""The RTC copy-write E2E may touch ONLY the disposable scratch copy; every real database path must be refused before any connection is opened."""
+import importlib.util
+import sys
+from pathlib import Path
+
+import pytest
+
+ROOT = Path(__file__).resolve().parents[1]
+
+
+def _load():
+ sys.path.insert(0, str(ROOT / "scripts")); sys.path.insert(0, str(ROOT / "agent" / "src"))
+ spec = importlib.util.spec_from_file_location("rtc_copy_write_e2e", ROOT / "scripts" / "rtc_copy_write_e2e.py")
+ module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(module)
+ return module
+
+
+def test_guard_accepts_only_the_exact_scratch_copy_and_refuses_real_databases():
+ module = _load()
+ module.guard(module.COPY) # the copy itself is fine
+ for path in (ROOT / "TESTESOFICIAIS.FDB", ROOT / "Banco" / "CONSTRUCAO.FDB", ROOT / "Banco" / "RINCAO.FDB", ROOT / "scratch_rtc_e2e" / "OTHER.FDB", Path("D:/PROJETOS/GTISISTEMAS/Banco/GTI.FDB")):
+ with pytest.raises(SystemExit):
+ module.guard(str(path))
+ assert "scratch_rtc_e2e" in module.COPY
+
+
+def test_the_e2e_script_only_ever_connects_to_the_copy():
+ text = (ROOT / "scripts" / "rtc_copy_write_e2e.py").read_text(encoding="utf-8")
+ assert text.count("fdb.connect(") == 1 and "database=COPY" in text # the single connection helper is bound to the copy path