Files
siloqy/prod/clean_arch/violet/observe_guard.py

72 lines
2.6 KiB
Python
Raw Normal View History

"""VIOLET observe-only hard guard (Stage V1).
``ObserveOnlyVenue`` wraps any venue adapter and makes order placement
structurally impossible: ``submit``/``submit_async``/``cancel``/
``cancel_async`` raise ``ObserveOnlyViolation`` and log CRITICAL. Every
other attribute (including assignment e.g. the runtime's
``venue._kernel_ref = kernel``) delegates to the wrapped adapter, so
account streams, reconcile reads and connection management work unchanged.
This is the hard guarantee, independent of policy configuration: even if a
policy step were ever wired into the V1 runtime by mistake, no order can
reach the exchange.
"""
from __future__ import annotations
import logging
from typing import Any
LOGGER = logging.getLogger("violet.observe_guard")
_BLOCKED = ("submit", "submit_async", "cancel", "cancel_async")
_SELF_ATTRS = ("_inner", "_logger")
class ObserveOnlyViolation(RuntimeError):
"""An order-placement call reached the observe-only venue guard."""
class ObserveOnlyVenue:
"""Delegating wrapper that refuses order placement."""
def __init__(self, inner: Any, logger: logging.Logger | None = None) -> None:
object.__setattr__(self, "_inner", inner)
object.__setattr__(self, "_logger", logger or LOGGER)
# -- blocked surface -----------------------------------------------------
def _refuse(self, name: str, *args: Any, **kwargs: Any) -> None:
msg = (
f"OBSERVE-ONLY VIOLATION: venue.{name}() called — VIOLET V1 must "
f"never place or cancel orders (args={args!r:.200})"
)
object.__getattribute__(self, "_logger").critical(msg)
raise ObserveOnlyViolation(msg)
def submit(self, *a: Any, **k: Any) -> Any:
self._refuse("submit", *a, **k)
async def submit_async(self, *a: Any, **k: Any) -> Any:
self._refuse("submit_async", *a, **k)
def cancel(self, *a: Any, **k: Any) -> Any:
self._refuse("cancel", *a, **k)
async def cancel_async(self, *a: Any, **k: Any) -> Any:
self._refuse("cancel_async", *a, **k)
# -- delegation ----------------------------------------------------------
def __getattr__(self, name: str) -> Any:
return getattr(object.__getattribute__(self, "_inner"), name)
def __setattr__(self, name: str, value: Any) -> None:
if name in _SELF_ATTRS:
object.__setattr__(self, name, value)
else:
setattr(object.__getattribute__(self, "_inner"), name, value)
def __repr__(self) -> str: # pragma: no cover — debug helper
return f"ObserveOnlyVenue({object.__getattribute__(self, '_inner')!r})"