#!/usr/bin/env python3 import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] ALLOWLIST = { ROOT / "splitup.md", ROOT / "scripts/check_no_monolith.py", } PATTERNS = [ (r"uvicorn\s+devplacepy\.main:app", "uvicorn monolith boot"), (r"from devplacepy\.main import", "main.py import"), (r"import devplacepy\.main", "main.py import"), (r"devplacepy\.main:app", "main app string"), (r"DEVPLACE_DB_MODE", "hybrid DB mode flag"), (r"make dev-monolith", "dev-monolith target"), (r"make prod-monolith", "prod-monolith target"), (r"DEVPLACE_TEST_PORT=10501", "legacy test port default"), (r"monolith-dev", "monolith port profile"), ] PHASE = sys.argv[1] if len(sys.argv) > 1 else "m7" def scan_file(path: Path) -> list[str]: if path in ALLOWLIST: return [] try: text = path.read_text(encoding="utf-8", errors="ignore") except OSError: return [] hits = [] for pattern, label in PATTERNS: if re.search(pattern, text): hits.append(f"{path.relative_to(ROOT)}: {label}") return hits def main() -> int: import subprocess db_check = subprocess.run( [sys.executable, str(ROOT / "scripts" / "check_database_imports.py")], capture_output=True, text=True, check=False, ) if db_check.returncode != 0: print(db_check.stdout or db_check.stderr) return 1 globs = [ "Makefile", "Dockerfile", "docker-compose*.yml", ".gitea/**/*.yaml", "CLAUDE.md", "README.md", "pyproject.toml", "devplacepy/**/*.py", "tests/**/*.py", "orchestrator.py", ] errors = [] for pattern in globs: for path in ROOT.glob(pattern): if path.is_file(): errors.extend(scan_file(path)) if PHASE in ("m3", "m6", "m7") and (ROOT / "devplacepy/main.py").exists(): if PHASE == "m7": errors.append("devplacepy/main.py: file must be deleted at M7") elif PHASE == "m3": pass if errors: print("MONOLITH ARTIFACTS FOUND:") for line in sorted(set(errors)): print(f" {line}") return 1 print("check_no_monolith: ok") return 0 if __name__ == "__main__": raise SystemExit(main())