"""Audit: fail if PROVIDERS is declared (as a literal list) anywhere except src/ai_client.py. The follow-up track's invariant: PROVIDERS lives in src/ai_client.py because it's the AI-client system constant (per the AGENTS.md HARD RULE on src/ files). The src/models.py re-export via __getattr__ is allowed (it's lazy-loaded, not a literal declaration). This audit catches accidental PROVIDERS literals that creep back in (e.g., a contributor adds a new vendor to src/models.py:PROVIDERS instead of src/ai_client.py:PROVIDERS). Usage: uv run python scripts/audit_providers_source_of_truth.py Exit code: 0 = pass; 1 = violation found. """ import re import sys from pathlib import Path ALLOWED_DECLARATION = Path("src/ai_client.py") PROVIDERS_LITERAL = re.compile(r"^PROVIDERS\s*:\s*List\[str\]\s*=\s*\[", re.MULTILINE) def main() -> int: violation: str = "" for path in Path("src").rglob("*.py"): text = path.read_text(encoding="utf-8") for match in PROVIDERS_LITERAL.finditer(text): if path != ALLOWED_DECLARATION: line_no = text[:match.start()].count("\n") + 1 violation = f"{path}:{line_no}: {match.group(0)}" break if violation: break if violation: print(f"FAIL: PROVIDERS declared outside {ALLOWED_DECLARATION}:") print(f" {violation}") print(f" Add the new vendor to {ALLOWED_DECLARATION} instead.") return 1 print(f"OK: PROVIDERS only declared in {ALLOWED_DECLARATION}") return 0 if __name__ == "__main__": sys.exit(main())