PINK DITAv2 Sprint 2-3: accounting parity + multi-leg groundwork
Sprint 2 (accounting + observability parity, PINK scope):
- Verified pink_clickhouse.py writes the 8 BLUE-legacy row families at
matching schema and that capital authority in pink_direct.step() is
solely kernel.account (no balance-poll overwrite in the hot loop).
- Report: prod/clean_arch/dita_v2/SPRINT2_ACCOUNTING_PARITY.md.
Sprint 3 offline groundwork (no exchange contact):
- Add _write_trade_exit_leg to pink_clickhouse.py: one BLUE-schema-faithful
trade_exit_legs row per exit leg, with isolated (non-cumulative) per-leg
deltas tracked via _leg_state (reset on ENTER). Closes the docstring gap.
- New offline suite test_pink_multi_exit_groundwork.py (3 passed):
* Flaw 4 — two-leg exit closes once, realized accrues per leg, closed
slot rejects further EXIT (no double-close).
* Overshoot invariant — a final EXIT requesting more than the remaining
size CLAMPS (size to 0, no oversell), retiring the Sprint 0 cumulative-
ratio risk empirically.
* trade_exit_legs delta + full BLUE column-set assertions.
- Persistence regression after edits: 10 passed.
BLUE untouched: no changes to dolphin.* / DOLPHIN_*_BLUE / nautilus_event_trader.py.
Live VST multi-leg run remains deferred pending explicit authorization.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
103
prod/launch_dita_v2.py
Normal file
103
prod/launch_dita_v2.py
Normal file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Operator-facing entrypoint for the DITAv2 kernel.
|
||||
|
||||
The launcher is env-driven and intentionally conservative by default:
|
||||
- mock venue
|
||||
- in-memory Zinc plane
|
||||
- callback projection
|
||||
- control-plane values may be overridden via DITA_V2_* env vars
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import signal
|
||||
import time
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
load_dotenv(PROJECT_ROOT / ".env")
|
||||
sys.path.insert(0, str(PROJECT_ROOT / "prod"))
|
||||
sys.path.insert(0, str(PROJECT_ROOT / "prod" / "clean_arch"))
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from prod.clean_arch.dita_v2.launcher import build_launcher_bundle
|
||||
|
||||
|
||||
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 _env_float(name: str, default: float) -> float:
|
||||
raw = os.environ.get(name)
|
||||
if raw is None:
|
||||
return default
|
||||
try:
|
||||
value = float(str(raw).strip())
|
||||
except Exception:
|
||||
return default
|
||||
return value if value > 0 else default
|
||||
|
||||
|
||||
def _env_mode() -> str:
|
||||
mode = str(os.environ.get("DITA_V2_LAUNCHER_MODE", "serve")).strip().lower()
|
||||
if mode in {"once", "serve"}:
|
||||
return mode
|
||||
return "serve"
|
||||
|
||||
|
||||
def _serve(bundle) -> int:
|
||||
interval = _env_float("DITA_V2_LAUNCHER_HEARTBEAT_SEC", 30.0)
|
||||
stop = False
|
||||
|
||||
def _handle_signal(signum, _frame) -> None:
|
||||
nonlocal stop
|
||||
stop = True
|
||||
|
||||
previous_term = signal.signal(signal.SIGTERM, _handle_signal)
|
||||
previous_int = signal.signal(signal.SIGINT, _handle_signal)
|
||||
try:
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"status": "serving",
|
||||
"control": bundle.kernel.control.as_dict(),
|
||||
"venue": type(bundle.venue).__name__,
|
||||
"zinc_plane": type(bundle.zinc_plane).__name__,
|
||||
"projection": type(bundle.projection).__name__,
|
||||
"heartbeat_sec": interval,
|
||||
},
|
||||
indent=2,
|
||||
sort_keys=True,
|
||||
default=str,
|
||||
)
|
||||
)
|
||||
while not stop:
|
||||
time.sleep(interval)
|
||||
return 0
|
||||
finally:
|
||||
signal.signal(signal.SIGTERM, previous_term)
|
||||
signal.signal(signal.SIGINT, previous_int)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
bundle = build_launcher_bundle()
|
||||
try:
|
||||
mode = _env_mode()
|
||||
if mode == "once" or _env_bool("DITA_V2_PRINT_SNAPSHOT", False):
|
||||
print(json.dumps(bundle.kernel.snapshot(), indent=2, sort_keys=True, default=str))
|
||||
return 0
|
||||
return _serve(bundle)
|
||||
finally:
|
||||
bundle.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user