#!/usr/bin/env python3 """Read-only audit of the exact Operations boundary in V1 and authoritative V2.""" from __future__ import annotations import json from pathlib import Path import sys ROOT = Path(__file__).resolve().parents[1] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from app.config import settings from app.operations_service import get_operations_summary JSON_PATH = Path("/tmp/blif_flow_v2_authoritative_simulation.json") TEXT_PATH = Path("/tmp/blif_flow_v2_authoritative_operations.txt") CURRENT = {"do_now", "review", "blocked", "exception"} def _all(summary): return list(summary.get("work_items") or []) + list(summary.get("waiting_items") or []) + list(summary.get("backlog_items") or []) + list(summary.get("not_current_items") or []) def _metrics(summary): items = _all(summary) queues = [str(item.get("operational_queue") or "") for item in items] return { "current": sum(queue in CURRENT for queue in queues), "do_now": queues.count("do_now"), "review": queues.count("review"), "waiting": queues.count("waiting"), "backlog": queues.count("backlog"), "not_current": queues.count("not_current"), } def _identity(item): return str(item.get("canonical_opportunity_id") or item.get("opportunity_id") or item.get("process_key") or item.get("work_item_key")) def _classification(old, new): if new is not None: return "REPLACED_BY_CORRECT_ACTION" decision = old.get("decision") or {} code = str(decision.get("reason_code") or old.get("eligibility_reason_code") or "").upper() if "DUPLICATE" in code: return "DUPLICATE_SUPPRESSED" if "SATISF" in code or "ANSWERED" in code: return "SATISFIED" if "SUPERSE" in code or "TERMINAL" in code: return "SUPERSEDED" if "PREMATURE" in code: return "PREMATURE_REMOVED" if old.get("source") in {"task", "opportunity"}: return "LEGACY_ONLY" return "UNSAFE_FALSE_NEGATIVE" def simulate(): original = settings.blif_flow_v2_mode try: settings.blif_flow_v2_mode = "off" v1 = get_operations_summary(limit=200) settings.blif_flow_v2_mode = "authoritative" v2 = get_operations_summary(limit=200) finally: settings.blif_flow_v2_mode = original v1_current = {_identity(item): item for item in _all(v1) if item.get("operational_queue") in CURRENT} v2_current = {_identity(item): item for item in _all(v2) if item.get("operational_queue") in CURRENT} removed = [] for key, old in v1_current.items(): new = v2_current.get(key) if new is None or new.get("action_code") != old.get("action_code"): removed.append({"identity": key, "v1_action": old.get("action_code"), "v2_action": (new or {}).get("action_code"), "classification": _classification(old, new)}) added = [{"identity": key, "action": item.get("action_code")} for key, item in v2_current.items() if key not in v1_current or v1_current[key].get("action_code") != item.get("action_code")] result = {"v1": _metrics(v1), "authoritative_v2": _metrics(v2), "cards_removed": removed, "cards_added_or_replaced": added, "unsafe_false_negatives": sum(row["classification"] == "UNSAFE_FALSE_NEGATIVE" for row in removed)} JSON_PATH.write_text(json.dumps(result, indent=2, ensure_ascii=False, default=str) + "\n") lines = ["BLIF Flow v2 authoritative Operations simulation", "", f"V1: {result['v1']}", f"Authoritative V2: {result['authoritative_v2']}", f"Cards removed: {len(removed)}", f"Cards added/replaced: {len(added)}", f"UNSAFE_FALSE_NEGATIVE: {result['unsafe_false_negatives']}"] TEXT_PATH.write_text("\n".join(lines) + "\n") return result if __name__ == "__main__": audit = simulate() print(json.dumps(audit, indent=2, ensure_ascii=False, default=str)) if audit["unsafe_false_negatives"]: raise SystemExit(2)