#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "$ROOT_DIR/scripts/harness/lib.sh" main() { cd "$ROOT_DIR" local uv_bin uv_bin="$(harness_require_tool uv)" harness_run "$uv_bin" run --frozen --project "$ROOT_DIR" python - <<'PY' import ast from pathlib import Path root = Path.cwd() failures: list[str] = [] def fail(message: str) -> None: failures.append(message) class BackendDebugCallVisitor(ast.NodeVisitor): def __init__(self, path: Path) -> None: self.path = path def visit_Call(self, node: ast.Call) -> None: if isinstance(node.func, ast.Name) and node.func.id in {"print", "breakpoint"}: fail(f"{self.path}:{node.lineno}: backend app code must use structured logging, not {node.func.id}()") if ( isinstance(node.func, ast.Attribute) and node.func.attr == "set_trace" and isinstance(node.func.value, ast.Name) and node.func.value.id == "pdb" ): fail(f"{self.path}:{node.lineno}: remove pdb.set_trace() from backend app code") self.generic_visit(node) for path in sorted((root / "backend/app").rglob("*.py")): rel = path.relative_to(root) try: tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(rel)) except SyntaxError as exc: fail(f"{rel}:{exc.lineno}: Python syntax error: {exc.msg}") continue BackendDebugCallVisitor(rel).visit(tree) if failures: for message in failures: print(f"fail: {message}") raise SystemExit(f"backend rules check failed: {len(failures)} failure(s)") print("backend rules check passed") PY } main "$@"