#!/usr/bin/env python3 """Rebuild additive BLIF Flow v2 projection tables with explicit safeguards.""" from __future__ import annotations import argparse import json import os import sys from pathlib import Path from typing import Sequence ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) os.chdir(ROOT) def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "--production-shadow", action="store_true", help="explicitly authorize projection-only shadow writes to database clientflow", ) return parser def validate_execution(*, production_shadow: bool, mode: str, database: str) -> None: """Validate CLI intent independently of DATABASE_URL inference.""" normalized_mode = str(mode or "").strip().lower() if production_shadow: if normalized_mode != "shadow": raise RuntimeError("--production-shadow requires BLIF_FLOW_V2_MODE=shadow") if database != "clientflow": raise RuntimeError( f"--production-shadow requires database 'clientflow', found {database!r}" ) return if database == "clientflow": raise RuntimeError("production database requires explicit --production-shadow opt-in") def main(argv: Sequence[str] | None = None) -> int: # argparse handles --help and exits before any application/DB import below. args = build_parser().parse_args(argv) from sqlalchemy import text from app.blif_flow_v2_projection_service import rebuild_blif_flow_v2_projection from app.config import settings from app.db import engine mode = str(settings.blif_flow_v2_mode or "").strip().lower() with engine.connect() as conn: identity = conn.execute(text( "SELECT current_database(), current_user, current_setting('transaction_read_only')" )).one() database, user, transaction_read_only = identity validate_execution( production_shadow=args.production_shadow, mode=mode, database=database, ) print(json.dumps({ "database": database, "user": user, "blif_flow_v2_mode": mode, "transaction_read_only": transaction_read_only, "production_shadow_opt_in": args.production_shadow, }, sort_keys=True), flush=True) if args.production_shadow: result = rebuild_blif_flow_v2_projection( mode="shadow", # Production is deliberately scoped to this invocation; the # module-level default allowlist remains test-only. allowed_databases=frozenset({"clientflow"}), derive_expected_database="clientflow", derive_expected_user=user, expected_opportunity_count=None, require_opportunities=True, ) else: result = rebuild_blif_flow_v2_projection() print(json.dumps(result, indent=2, sort_keys=True)) return 0 if __name__ == "__main__": raise SystemExit(main())