"""READ-ONLY phase timing of the Agent pipeline on a real database (default MMMODAS ~21k products) against the local dev Hub. Reports wall time per phase and peak RSS. python scripts/measure_scale_agent.py [--db MMMODAS]""" import argparse import json import os import sys import time from pathlib import Path ROOT = Path(__file__).resolve().parents[1] sys.path[:0] = [str(ROOT), str(ROOT / "scripts"), str(ROOT / "agent" / "src")] from dotenv import load_dotenv # noqa: E402 load_dotenv(ROOT / ".env") 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 from gti_fiscal_agent.client import HubClient # noqa: E402 from gti_fiscal_agent.runner import to_hub_product # noqa: E402 def rss_mb(): try: import psutil return round(psutil.Process().memory_info().rss / 1e6, 1) except Exception: # noqa: BLE001 return None def main(): ap = argparse.ArgumentParser(); ap.add_argument("--db", default="MMMODAS"); a = ap.parse_args() path = lc.allowlist()[a.db]; env = lc.env_for(path) out = {"database": a.db, "phases_seconds": {}} t = time.time(); products = firebird_reader.read_products(env); out["phases_seconds"]["firebird_read"] = round(time.time() - t, 2); out["products"] = len(products) t = time.time(); decisions = HubClient(os.environ.get("HUB_URL", lc.HUB), os.environ["AGENT_DEV_TOKEN"]).classify_batch([to_hub_product(p) for p in products]); out["phases_seconds"]["hub_classification"] = round(time.time() - t, 2) t = time.time(); states = [classify_product_state(p, d) for p, d in zip(products, decisions)]; summarize_operational_states(states); out["phases_seconds"]["operational_states"] = round(time.time() - t, 2) t = time.time(); conn = firebird_reader._connect(env) try: assessed = unified_fiscal.assess_from_connection(conn, {"crt": "1"}, rtc_override=None) finally: conn.close() out["phases_seconds"]["fiscal_rtc_pis_cofins_assessment"] = round(time.time() - t, 2) t = time.time(); payload = json.dumps({"operational": summarize_operational_states(states), "findings": len(assessed.get("findings", {}))}); out["phases_seconds"]["payload_generation"] = round(time.time() - t, 3) out["total_seconds"] = round(sum(out["phases_seconds"].values()), 2); out["peak_rss_mb"] = rss_mb(); out["products_per_second"] = round(len(products) / max(out["total_seconds"], 0.01), 1) print(json.dumps(out, indent=1)) (ROOT / "docs" / "runs" / "final_corpus" / f"scale_agent_{a.db}.json").write_text(json.dumps(out, indent=1), encoding="utf-8") if __name__ == "__main__": main()