File size: 4,508 Bytes
2e658e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/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())