#!/usr/bin/env python3 """Fail when execution authority depends on process/browser/file-only state.""" from __future__ import annotations import ast import re from pathlib import Path ROOT = Path(__file__).resolve().parents[1] # Explicitly bounded cache/state. This dashboard snapshot cannot authorize a # financial mutation; all execution boundaries re-read relational records. ALLOWED_MUTABLE_GLOBALS = { "hermes_overlay/trading/state.py": {"_state"}, } FORBIDDEN_BROWSER_AUTHORITY = { "positions", "plan", "approval", "executionEnabled", "leverage", "accountId", "tradingMode", "killSwitch", } AUTHORITY_NAME_TOKENS = { "position", "order", "approval", "idempot", "execution_service", "pnl", "leverage", "protective", "financial_state", "trade_book", } LEGACY_FILE_MARKERS = {"paper_positions.json", "paper_state.json"} def _assigned_names(node: ast.Assign | ast.AnnAssign) -> list[str]: targets = node.targets if isinstance(node, ast.Assign) else [node.target] names: list[str] = [] for target in targets: if isinstance(target, ast.Name): names.append(target.id) return names def _mutable_or_instance(value: ast.AST | None) -> bool: return isinstance(value, (ast.Dict, ast.List, ast.Set, ast.Call, ast.DictComp, ast.ListComp, ast.SetComp)) def _is_constant_name(name: str) -> bool: return name.lstrip("_").isupper() def audit(root: Path = ROOT) -> list[str]: errors: list[str] = [] runtime_roots = [root / "hermes_overlay" / "trading", root / "hermes_overlay" / "tools"] for base in runtime_roots: if not base.exists(): continue for path in sorted(base.rglob("*.py")): if "tests" in path.parts or "__pycache__" in path.parts: continue rel = path.relative_to(root).as_posix() text = path.read_text(encoding="utf-8") allowed = ALLOWED_MUTABLE_GLOBALS.get(rel, set()) try: tree = ast.parse(text, filename=rel) except SyntaxError as exc: errors.append(f"cannot audit invalid Python: {rel}:{exc.lineno}") continue for node in tree.body: if not isinstance(node, (ast.Assign, ast.AnnAssign)): continue value = node.value if not _mutable_or_instance(value): continue for name in _assigned_names(node): if name in allowed or _is_constant_name(name): continue lowered = name.lower() if any(token in lowered for token in AUTHORITY_NAME_TOKENS): errors.append(f"unapproved module financial authority: {rel}:{name}") if rel.endswith("durable_store.py"): # Explicitly isolated legacy inspection facade. Runtime imports # are forbidden below and one-way import tooling handles data. pass elif "hermes_durable.sqlite3" in text: errors.append(f"runtime references legacy flat database: {rel}") for marker in LEGACY_FILE_MARKERS: if marker in text: errors.append(f"runtime references legacy financial state file: {rel}:{marker}") if re.search(r"\bfrom\s+trading\.durable_store\b|\bimport\s+trading\.durable_store\b", text): errors.append(f"runtime imports legacy compatibility store: {rel}") template = root / "hermes_overlay/tools/templates/hermes_futures_desk_luxury.html" if not template.is_file(): errors.append("dashboard template missing") return errors text = template.read_text(encoding="utf-8") for key in FORBIDDEN_BROWSER_AUTHORITY: pattern = rf"localStorage\.setItem\(\s*['\"]{re.escape(key)}['\"]" if re.search(pattern, text): errors.append(f"browser stores authoritative key: {key}") # Theme and presentation preferences are explicitly non-authoritative. if "localStorage.setItem('hermes_theme'" not in text: errors.append("expected non-authoritative theme preference contract missing") return errors def main() -> int: errors = audit() for error in errors: print(f"ERROR: {error}") print(f"authoritative_state_audit={'PASS' if not errors else 'FAIL'} findings={len(errors)}") return 1 if errors else 0 if __name__ == "__main__": raise SystemExit(main())