Snapshot PINK DITAv2 system + Sprint 0 flaw-fix verification

First commit of the previously-untracked PINK-on-DITAv2 migration system
(execution moves to the Rust kernel; policy stays on legacy DITA, so Alpha
Engine algorithmic integrity is preserved). BLUE is untouched.

Sprint 0 (safety snapshot + flaw-fix verification, MARKET single-leg scope):
- Verified Rust FSM fixes (flaws 2,4,10,11,13) by source read of lib.rs.
- Hardened 5 vacuous/guarded assertions in test_flaws.py so each flaw test
  genuinely exercises its fix. Most important: Flaw 5 now asserts capital
  moves by EXACTLY realized PnL (was entering/exiting at the same price).
- Offline suites: 533 passed, 0 failed (35 flaws + 402 kernel/accounting/
  bridge + 96 runtime/persistence/multi-exit/restart/seams).
- GATE PASS: MARKET-path-critical flaws 1,2,5 confirmed fixed + green.
- Added SPRINT0_FLAW_VERIFICATION.md report and _rust_kernel/.gitignore
  (excludes Rust target/ build artifacts).

LIMIT/partial-fill remain explicitly out of scope (MARKET-only bring-up).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Codex
2026-05-30 18:26:43 +02:00
parent 34d01fe6a4
commit 3d7b00e28d
89 changed files with 32782 additions and 0 deletions

View File

@@ -0,0 +1,350 @@
"""Operator-facing bootstrap helpers for DITAv2.
This module keeps the wiring explicit:
- control plane selection
- Zinc plane selection
- projection sink selection
- venue adapter selection
The defaults stay safe and testable. Real shared-memory or live BingX wiring
is only enabled when the caller opts in via arguments or environment.
"""
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
import asyncio
import inspect
import os
from pathlib import Path
from typing import Any, Optional
from dotenv import load_dotenv
from prod.bingx.config import BingxExecClientConfig
from prod.bingx.config import BingxInstrumentProviderConfig
from prod.bingx.enums import BingxEnvironment
from .bingx_venue import BingxVenueAdapter
from .control import BackendMode
from .control import ControlPlane
from .control import ControlUpdate
from .control import KernelControlSnapshot
from .control import KernelMode
from .control import KernelVerbosity
from .control import build_control_plane
from .mock_venue import MockVenueAdapter
from .mock_venue import MockVenueScenario
from .projection import HazelcastProjection
from .projection import build_projection
from .real_control_plane import RealZincControlPlane
from .real_control_plane import RealZincUnavailable
from .real_zinc_plane import RealZincPlane
from .real_zinc_plane import RealZincUnavailable as RealZincPlaneUnavailable
from .rust_backend import ExecutionKernel
from .venue import VenueAdapter
from .zinc_plane import InMemoryZincPlane
from .zinc_plane import ZincPlane
PROJECT_ROOT = Path(__file__).resolve().parents[3]
load_dotenv(PROJECT_ROOT / ".env")
class LauncherVenueMode(str, Enum):
MOCK = "MOCK"
BINGX = "BINGX"
class LauncherZincMode(str, Enum):
IN_MEMORY = "IN_MEMORY"
REAL = "REAL"
@dataclass
class DITAv2LauncherBundle:
"""Concrete runtime components assembled by the launcher."""
kernel: ExecutionKernel
control_plane: ControlPlane
projection: HazelcastProjection
zinc_plane: ZincPlane
venue: VenueAdapter
def close(self) -> None:
_maybe_close(self.venue)
_maybe_close(self.zinc_plane)
_maybe_close(self.control_plane)
def _env_upper(name: str, default: str = "") -> str:
return str(os.environ.get(name, default)).strip().upper()
def _env_bool(name: str, default: bool = False) -> bool:
raw = os.environ.get(name)
if raw is None:
return default
return str(raw).strip().lower() in {"1", "true", "yes", "on"}
def _resolve_control_mode() -> KernelMode | None:
raw = _env_upper("DITA_V2_MODE", "")
if raw == KernelMode.DEBUG.value:
return KernelMode.DEBUG
if raw == KernelMode.NORMAL.value:
return KernelMode.NORMAL
return None
def _resolve_control_verbosity() -> KernelVerbosity | None:
raw = _env_upper("DITA_V2_VERBOSITY", "")
if raw == KernelVerbosity.TRACE.value:
return KernelVerbosity.TRACE
if raw == KernelVerbosity.VERBOSE.value:
return KernelVerbosity.VERBOSE
if raw == KernelVerbosity.QUIET.value:
return KernelVerbosity.QUIET
return None
def _resolve_backend_mode() -> BackendMode | None:
raw = _env_upper("DITA_V2_BACKEND_MODE", "")
if raw == BackendMode.BINGX.value:
return BackendMode.BINGX
if raw == BackendMode.MOCK.value:
return BackendMode.MOCK
return None
def _control_update_from_env() -> ControlUpdate | None:
fields: dict[str, Any] = {}
mode = _resolve_control_mode()
if mode is not None:
fields["mode"] = mode
verbosity = _resolve_control_verbosity()
if verbosity is not None:
fields["verbosity"] = verbosity
backend_mode = _resolve_backend_mode()
if backend_mode is not None:
fields["backend_mode"] = backend_mode
raw = os.environ.get("DITA_V2_DEBUG_CLICKHOUSE")
if raw is not None:
fields["debug_clickhouse_enabled"] = _env_bool("DITA_V2_DEBUG_CLICKHOUSE", True)
raw = os.environ.get("DITA_V2_TRACE_TRANSITIONS")
if raw is not None:
fields["trace_transitions"] = _env_bool("DITA_V2_TRACE_TRANSITIONS", False)
raw = os.environ.get("DITA_V2_MIRROR_TO_HAZELCAST")
if raw is not None:
fields["mirror_to_hazelcast"] = _env_bool("DITA_V2_MIRROR_TO_HAZELCAST", True)
raw = os.environ.get("DITA_V2_ACTIVE_SLOT_LIMIT")
if raw is not None:
try:
fields["active_slot_limit"] = max(1, int(str(raw).strip()))
except Exception:
pass
raw = os.environ.get("DITA_V2_RECONCILE_ON_RESTART")
if raw is not None:
fields["reconcile_on_restart"] = _env_bool("DITA_V2_RECONCILE_ON_RESTART", True)
return ControlUpdate(**fields) if fields else None
def _resolve_venue_mode(venue_mode: Optional[str] = None) -> LauncherVenueMode:
raw = _env_upper("DITA_V2_VENUE", venue_mode or LauncherVenueMode.MOCK.value)
if raw == LauncherVenueMode.BINGX.value:
return LauncherVenueMode.BINGX
return LauncherVenueMode.MOCK
def _resolve_zinc_mode(zinc_mode: Optional[str] = None) -> LauncherZincMode:
raw = _env_upper("DITA_V2_ZINC", zinc_mode or LauncherZincMode.IN_MEMORY.value)
if raw == LauncherZincMode.REAL.value:
return LauncherZincMode.REAL
return LauncherZincMode.IN_MEMORY
def _resolve_hazelcast_real(prefer_real_hazelcast: Optional[bool] = None) -> bool:
if prefer_real_hazelcast is not None:
return bool(prefer_real_hazelcast)
raw = _env_upper("DITA_V2_HAZELCAST", "")
return raw in {"REAL", "REAL_HZ", "HAZELCAST"}
def build_bingx_exec_client_config(
*,
environment: Optional[BingxEnvironment] = None,
allow_mainnet: Optional[bool] = None,
recv_window_ms: Optional[int] = None,
default_leverage: Optional[int] = None,
exchange_leverage_cap: Optional[int] = None,
prefer_websocket: Optional[bool] = None,
sizing_mode: Optional[str] = None,
) -> BingxExecClientConfig:
"""Build the direct BingX config used by the DITAv2 launcher."""
resolved_environment = environment or (
BingxEnvironment.LIVE if _env_upper("DOLPHIN_BINGX_ENV", "VST") == "LIVE" else BingxEnvironment.VST
)
resolved_allow_mainnet = _env_bool("DOLPHIN_BINGX_ALLOW_MAINNET", False) if allow_mainnet is None else bool(allow_mainnet)
resolved_recv_window = int(os.environ.get("DOLPHIN_BINGX_RECV_WINDOW_MS", "5000")) if recv_window_ms is None else int(recv_window_ms)
resolved_default_leverage = int(os.environ.get("DOLPHIN_BINGX_DEFAULT_LEVERAGE", "1")) if default_leverage is None else int(default_leverage)
resolved_exchange_cap = int(os.environ.get("DOLPHIN_BINGX_EXCHANGE_LEVERAGE_CAP", "3")) if exchange_leverage_cap is None else int(exchange_leverage_cap)
resolved_prefer_ws = _env_bool("DOLPHIN_BINGX_PREFER_WEBSOCKET", False) if prefer_websocket is None else bool(prefer_websocket)
resolved_sizing_mode = sizing_mode or os.environ.get("DOLPHIN_BINGX_SIZING_MODE", "testnet")
return BingxExecClientConfig(
api_key=os.environ.get("BINGX_API_KEY"),
secret_key=os.environ.get("BINGX_SECRET_KEY"),
environment=resolved_environment,
allow_mainnet=resolved_allow_mainnet,
recv_window_ms=max(1, resolved_recv_window),
default_leverage=max(1, resolved_default_leverage),
exchange_leverage_cap=max(1, resolved_exchange_cap),
prefer_websocket=resolved_prefer_ws,
sizing_mode=resolved_sizing_mode,
journal_strategy=os.environ.get("DOLPHIN_BINGX_JOURNAL_STRATEGY", "dita_v2"),
journal_db=os.environ.get("DOLPHIN_BINGX_JOURNAL_DB", "dolphin_pink"),
instrument_provider=BingxInstrumentProviderConfig(load_all=True),
)
def _build_control_plane(
*,
prefix: str,
control_plane: Optional[ControlPlane] = None,
) -> ControlPlane:
plane = control_plane or build_control_plane(prefix=prefix)
update = _control_update_from_env()
if update is not None:
plane.update(update)
return plane
def _build_zinc_plane(
*,
prefix: str,
slot_count: int,
zinc_mode: Optional[LauncherZincMode] = None,
zinc_plane: Optional[ZincPlane] = None,
) -> ZincPlane:
if zinc_plane is not None:
return zinc_plane
resolved_mode = zinc_mode or _resolve_zinc_mode()
if resolved_mode is LauncherZincMode.REAL:
try:
return RealZincPlane(prefix=prefix, slot_count=slot_count, create=True)
except (RealZincPlaneUnavailable, RealZincUnavailable, Exception):
pass
return InMemoryZincPlane()
def _build_venue(
*,
venue_mode: Optional[LauncherVenueMode] = None,
mock_scenario: Optional[MockVenueScenario] = None,
bingx_config: Optional[BingxExecClientConfig] = None,
bingx_backend: Optional[Any] = None,
venue: Optional[VenueAdapter] = None,
) -> VenueAdapter:
if venue is not None:
return venue
resolved_mode = venue_mode or _resolve_venue_mode()
if resolved_mode is LauncherVenueMode.BINGX:
backend = bingx_backend
if backend is None:
from prod.clean_arch.adapters.bingx_direct import BingxDirectExecutionAdapter
backend = BingxDirectExecutionAdapter(bingx_config or build_bingx_exec_client_config())
return BingxVenueAdapter(backend=backend)
return MockVenueAdapter(mock_scenario)
def _maybe_close(obj: Any) -> None:
for method_name in ("close", "disconnect"):
method = getattr(obj, method_name, None)
if method is None:
continue
try:
result = method()
except TypeError:
continue
if inspect.isawaitable(result):
try:
asyncio.run(result)
except RuntimeError:
pass
break
def build_launcher_bundle(
*,
max_slots: int = 10,
prefix: Optional[str] = None,
control_plane: Optional[ControlPlane] = None,
projection: Optional[HazelcastProjection] = None,
projection_client: Optional[Any] = None,
zinc_plane: Optional[ZincPlane] = None,
venue: Optional[VenueAdapter] = None,
venue_mode: Optional[LauncherVenueMode | str] = None,
zinc_mode: Optional[LauncherZincMode | str] = None,
bingx_config: Optional[BingxExecClientConfig] = None,
bingx_backend: Optional[Any] = None,
mock_scenario: Optional[MockVenueScenario] = None,
) -> DITAv2LauncherBundle:
"""Build a fully wired DITAv2 runtime bundle.
Defaults stay non-destructive:
- in-memory Zinc plane
- in-process control plane
- mock venue
- callback projection unless a Hazelcast client is supplied
"""
resolved_prefix = (prefix or os.environ.get("DITA_V2_PREFIX", "dita_v2")).strip() or "dita_v2"
if isinstance(venue_mode, LauncherVenueMode):
resolved_venue_mode = venue_mode
elif isinstance(venue_mode, str):
resolved_venue_mode = LauncherVenueMode(venue_mode.strip().upper())
else:
resolved_venue_mode = None
if isinstance(zinc_mode, LauncherZincMode):
resolved_zinc_mode = zinc_mode
elif isinstance(zinc_mode, str):
resolved_zinc_mode = LauncherZincMode(zinc_mode.strip().upper())
else:
resolved_zinc_mode = None
active_control_plane = _build_control_plane(prefix=resolved_prefix, control_plane=control_plane)
control_snapshot = active_control_plane.read()
active_projection = projection or build_projection(
client=projection_client,
prefer_real_hazelcast=_resolve_hazelcast_real(),
control_snapshot=control_snapshot,
)
active_zinc_plane = _build_zinc_plane(
prefix=resolved_prefix,
slot_count=int(max_slots),
zinc_mode=resolved_zinc_mode,
zinc_plane=zinc_plane,
)
active_venue = _build_venue(
venue_mode=resolved_venue_mode,
mock_scenario=mock_scenario,
bingx_config=bingx_config,
bingx_backend=bingx_backend,
venue=venue,
)
kernel = ExecutionKernel(
max_slots=int(max_slots),
control_plane=active_control_plane,
venue=active_venue,
projection=active_projection,
projection_client=projection_client,
zinc_plane=active_zinc_plane,
)
return DITAv2LauncherBundle(
kernel=kernel,
control_plane=active_control_plane,
projection=active_projection,
zinc_plane=active_zinc_plane,
venue=active_venue,
)