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:
380
prod/tests/test_dita_v2_zinc.py
Normal file
380
prod/tests/test_dita_v2_zinc.py
Normal file
@@ -0,0 +1,380 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
import os
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
from uuid import uuid4
|
||||
|
||||
from prod.clean_arch.dita_v2 import (
|
||||
ControlUpdate,
|
||||
ExecutionKernel,
|
||||
InMemoryControlPlane,
|
||||
KernelCommandType,
|
||||
KernelDiagnosticCode,
|
||||
KernelControlSnapshot,
|
||||
KernelIntent,
|
||||
KernelMode,
|
||||
KernelVerbosity,
|
||||
MockVenueAdapter,
|
||||
MockVenueScenario,
|
||||
InMemoryZincPlane,
|
||||
RealZincPlane,
|
||||
RealZincControlPlane,
|
||||
RealZincUnavailable,
|
||||
TradeSide,
|
||||
TradeSlot,
|
||||
TradeStage,
|
||||
VenueEvent,
|
||||
VenueEventStatus,
|
||||
KernelEventKind,
|
||||
)
|
||||
from prod.clean_arch.dita_v2.real_zinc_plane import SharedRegion
|
||||
|
||||
|
||||
HAS_REAL_ZINC = SharedRegion is not None
|
||||
|
||||
|
||||
def mk_intent_kwargs(
|
||||
*,
|
||||
slot_id: int,
|
||||
trade_id: str,
|
||||
action: KernelCommandType,
|
||||
size: float = 1.0,
|
||||
leverage: float = 2.0,
|
||||
side: TradeSide = TradeSide.SHORT,
|
||||
price: float = 100.0,
|
||||
reason: str = "FUZZ",
|
||||
) -> dict[str, object]:
|
||||
return {
|
||||
"timestamp": datetime.now(timezone.utc),
|
||||
"intent_id": f"intent-{trade_id}-{action.value}-{slot_id}",
|
||||
"trade_id": trade_id,
|
||||
"slot_id": slot_id,
|
||||
"asset": "BTCUSDT",
|
||||
"side": side,
|
||||
"action": action,
|
||||
"reference_price": price,
|
||||
"target_size": size,
|
||||
"leverage": leverage,
|
||||
"exit_leg_ratios": (0.5, 0.5) if action == KernelCommandType.EXIT else (1.0,),
|
||||
"reason": reason,
|
||||
}
|
||||
|
||||
|
||||
@unittest.skipUnless(HAS_REAL_ZINC, "Real Zinc adapter is unavailable")
|
||||
class TestDITAv2RealZinc(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.prefix = f"dita_v2_{os.getpid()}_{uuid4().hex}"
|
||||
self.writer = RealZincPlane(prefix=self.prefix, slot_count=3, create=True)
|
||||
self.reader = RealZincPlane(prefix=self.prefix, slot_count=3, create=False)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.writer.close()
|
||||
self.reader.close()
|
||||
|
||||
def _slot_dicts(self, plane: RealZincPlane) -> list[dict[str, object]]:
|
||||
return [slot.to_dict() for slot in plane.read_slots()]
|
||||
|
||||
def test_wait_notify_and_roundtrip(self) -> None:
|
||||
waiter_started = threading.Event()
|
||||
waiter_result: dict[str, bool] = {"ok": False}
|
||||
|
||||
def _waiter() -> None:
|
||||
waiter_started.set()
|
||||
waiter_result["ok"] = self.reader.wait_on_state(timeout_ms=3000)
|
||||
|
||||
thread = threading.Thread(target=_waiter, daemon=True)
|
||||
thread.start()
|
||||
self.assertTrue(waiter_started.wait(timeout=2.0))
|
||||
time.sleep(0.05)
|
||||
|
||||
kernel_slot = self.writer.read_slots()
|
||||
self.assertEqual(len(kernel_slot), 3)
|
||||
self.assertTrue(all(slot.fsm_state == TradeStage.IDLE for slot in kernel_slot))
|
||||
self.writer.write_slot(
|
||||
TradeSlot(
|
||||
slot_id=0,
|
||||
trade_id="trade-zinc-1",
|
||||
asset="BTCUSDT",
|
||||
side=TradeSide.SHORT,
|
||||
entry_price=100.0,
|
||||
size=1.0,
|
||||
initial_size=1.0,
|
||||
leverage=2.0,
|
||||
fsm_state=TradeStage.POSITION_OPEN,
|
||||
)
|
||||
)
|
||||
thread.join(timeout=3.0)
|
||||
self.assertFalse(thread.is_alive())
|
||||
self.assertTrue(waiter_result["ok"])
|
||||
slots = self.reader.read_slots()
|
||||
self.assertEqual(len(slots), 3)
|
||||
self.assertEqual(slots[0].trade_id, "trade-zinc-1")
|
||||
self.assertEqual(slots[0].fsm_state, TradeStage.POSITION_OPEN)
|
||||
self.assertTrue(all(slot.fsm_state == TradeStage.IDLE for slot in slots[1:]))
|
||||
|
||||
def test_in_memory_wait_notify_matches_signal_semantics(self) -> None:
|
||||
plane = InMemoryZincPlane()
|
||||
waiter_started = threading.Event()
|
||||
waiter_result: dict[str, bool] = {"ok": False}
|
||||
|
||||
def _waiter() -> None:
|
||||
waiter_started.set()
|
||||
waiter_result["ok"] = plane.wait_on_state(timeout_ms=2000)
|
||||
|
||||
thread = threading.Thread(target=_waiter, daemon=True)
|
||||
thread.start()
|
||||
self.assertTrue(waiter_started.wait(timeout=2.0))
|
||||
time.sleep(0.05)
|
||||
plane.write_slot(
|
||||
TradeSlot(
|
||||
slot_id=0,
|
||||
trade_id="trade-signal",
|
||||
asset="BTCUSDT",
|
||||
side=TradeSide.LONG,
|
||||
entry_price=101.0,
|
||||
size=1.0,
|
||||
initial_size=1.0,
|
||||
leverage=2.0,
|
||||
fsm_state=TradeStage.POSITION_OPEN,
|
||||
)
|
||||
)
|
||||
thread.join(timeout=3.0)
|
||||
self.assertFalse(thread.is_alive())
|
||||
self.assertTrue(waiter_result["ok"])
|
||||
|
||||
def test_real_control_plane_roundtrip_uses_open_existing_region(self) -> None:
|
||||
prefix = f"dita_v2_control_{os.getpid()}_{uuid4().hex}"
|
||||
plane = RealZincPlane(prefix=prefix, slot_count=1, create=True)
|
||||
control = RealZincControlPlane(prefix=prefix, create=False)
|
||||
try:
|
||||
snapshot = control.read()
|
||||
self.assertEqual(getattr(snapshot.mode, "value", snapshot.mode), KernelMode.NORMAL.value)
|
||||
self.assertEqual(getattr(snapshot.verbosity, "value", snapshot.verbosity), KernelVerbosity.QUIET.value)
|
||||
updated = control.update(ControlUpdate(mode=KernelMode.DEBUG, verbosity=KernelVerbosity.TRACE))
|
||||
self.assertEqual(getattr(updated.mode, "value", updated.mode), KernelMode.DEBUG.value)
|
||||
self.assertEqual(getattr(updated.verbosity, "value", updated.verbosity), KernelVerbosity.TRACE.value)
|
||||
mirrored = plane.read_control()
|
||||
self.assertEqual(getattr(mirrored.mode, "value", mirrored.mode), KernelMode.DEBUG.value)
|
||||
self.assertEqual(getattr(mirrored.verbosity, "value", mirrored.verbosity), KernelVerbosity.TRACE.value)
|
||||
finally:
|
||||
control.close()
|
||||
plane.close()
|
||||
|
||||
def test_real_control_plane_create_conflicts_with_existing_zinc_plane(self) -> None:
|
||||
prefix = f"dita_v2_conflict_{os.getpid()}_{uuid4().hex}"
|
||||
plane = RealZincPlane(prefix=prefix, slot_count=1, create=True)
|
||||
try:
|
||||
with self.assertRaises(FileExistsError):
|
||||
RealZincControlPlane(prefix=prefix, create=True)
|
||||
finally:
|
||||
plane.close()
|
||||
|
||||
def test_kernel_accepts_real_control_plane_snapshot_strings(self) -> None:
|
||||
prefix = f"dita_v2_kernel_real_cp_{os.getpid()}_{uuid4().hex}"
|
||||
plane = RealZincPlane(prefix=prefix, slot_count=1, create=True)
|
||||
control = RealZincControlPlane(prefix=prefix, create=False)
|
||||
try:
|
||||
kernel = ExecutionKernel(
|
||||
max_slots=1,
|
||||
control_plane=control,
|
||||
venue=MockVenueAdapter(MockVenueScenario(emit_fill_on_submit=True, partial_fill_ratio=1.0)),
|
||||
zinc_plane=plane,
|
||||
)
|
||||
kernel.update_control(
|
||||
ControlUpdate(
|
||||
mode=KernelMode.DEBUG,
|
||||
verbosity=KernelVerbosity.TRACE,
|
||||
trace_transitions=True,
|
||||
)
|
||||
)
|
||||
outcome = kernel.process_intent(
|
||||
KernelIntent(
|
||||
**mk_intent_kwargs(
|
||||
slot_id=0,
|
||||
trade_id=f"trade-real-cp-{uuid4().hex}",
|
||||
action=KernelCommandType.ENTER,
|
||||
price=100.0,
|
||||
size=1.0,
|
||||
)
|
||||
)
|
||||
)
|
||||
self.assertTrue(outcome.accepted)
|
||||
self.assertEqual(outcome.diagnostic_code, KernelDiagnosticCode.OK)
|
||||
self.assertEqual(kernel.slot(0).fsm_state, TradeStage.POSITION_OPEN)
|
||||
self.assertEqual(getattr(kernel.control.mode, "value", kernel.control.mode), KernelMode.DEBUG.value)
|
||||
self.assertEqual(getattr(kernel.control.verbosity, "value", kernel.control.verbosity), KernelVerbosity.TRACE.value)
|
||||
finally:
|
||||
control.close()
|
||||
plane.close()
|
||||
|
||||
def test_kernel_and_zinc_fuzz_roundtrip_150_checks(self) -> None:
|
||||
control = InMemoryControlPlane(
|
||||
KernelControlSnapshot(mode=KernelMode.DEBUG, verbosity=KernelVerbosity.TRACE)
|
||||
)
|
||||
kernel = ExecutionKernel(
|
||||
max_slots=3,
|
||||
control_plane=control,
|
||||
venue=MockVenueAdapter(MockVenueScenario(emit_fill_on_submit=True, partial_fill_ratio=1.0)),
|
||||
zinc_plane=self.writer,
|
||||
)
|
||||
rng = random.Random(20260526)
|
||||
|
||||
for i in range(150):
|
||||
slot_id = rng.randrange(0, 3)
|
||||
slot = kernel.slot(slot_id)
|
||||
op = rng.choice(
|
||||
[
|
||||
"enter",
|
||||
"exit",
|
||||
"mark",
|
||||
"reconcile",
|
||||
"control",
|
||||
"event",
|
||||
]
|
||||
)
|
||||
|
||||
with self.subTest(iteration=i, slot=slot_id, op=op):
|
||||
if op == "enter":
|
||||
if slot.is_free():
|
||||
kernel.process_intent(
|
||||
KernelIntent(
|
||||
**mk_intent_kwargs(
|
||||
slot_id=slot_id,
|
||||
trade_id=f"trade-{slot_id}-{i}",
|
||||
action=KernelCommandType.ENTER,
|
||||
price=100.0 + rng.random(),
|
||||
size=1.0 + (rng.random() * 0.5),
|
||||
leverage=1.5 + (rng.random() * 2.0),
|
||||
)
|
||||
)
|
||||
)
|
||||
elif op == "exit":
|
||||
if slot.is_open():
|
||||
kernel.process_intent(
|
||||
KernelIntent(
|
||||
**mk_intent_kwargs(
|
||||
slot_id=slot_id,
|
||||
trade_id=slot.trade_id,
|
||||
action=KernelCommandType.EXIT,
|
||||
price=99.0 + rng.random(),
|
||||
size=max(0.1, slot.size or 0.1),
|
||||
leverage=slot.leverage or 2.0,
|
||||
)
|
||||
)
|
||||
)
|
||||
elif op == "mark":
|
||||
kernel.process_intent(
|
||||
KernelIntent(
|
||||
**mk_intent_kwargs(
|
||||
slot_id=slot_id,
|
||||
trade_id=slot.trade_id or f"trade-{slot_id}-{i}",
|
||||
action=KernelCommandType.MARK_PRICE,
|
||||
price=95.0 + rng.random() * 10.0,
|
||||
size=max(slot.size, 1.0) if slot.size > 0 else 1.0,
|
||||
leverage=slot.leverage or 2.0,
|
||||
)
|
||||
)
|
||||
)
|
||||
elif op == "reconcile":
|
||||
kernel.process_intent(
|
||||
KernelIntent(
|
||||
**mk_intent_kwargs(
|
||||
slot_id=slot_id,
|
||||
trade_id=slot.trade_id or f"trade-{slot_id}-{i}",
|
||||
action=KernelCommandType.RECONCILE,
|
||||
price=100.0,
|
||||
size=max(slot.size, 1.0) if slot.size > 0 else 1.0,
|
||||
leverage=slot.leverage or 2.0,
|
||||
)
|
||||
)
|
||||
)
|
||||
elif op == "control":
|
||||
kernel.update_control(
|
||||
ControlUpdate(
|
||||
mode=KernelMode.DEBUG if rng.random() < 0.7 else KernelMode.NORMAL,
|
||||
verbosity=KernelVerbosity.TRACE if rng.random() < 0.5 else KernelVerbosity.VERBOSE,
|
||||
trace_transitions=rng.random() < 0.5,
|
||||
)
|
||||
)
|
||||
elif op == "event":
|
||||
current = kernel.slot(slot_id)
|
||||
if current.active_entry_order is not None:
|
||||
event = VenueEvent(
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
event_id=f"evt-{i}-{slot_id}",
|
||||
trade_id=current.trade_id,
|
||||
slot_id=slot_id,
|
||||
kind=rng.choice(
|
||||
[
|
||||
KernelEventKind.ORDER_ACK,
|
||||
KernelEventKind.PARTIAL_FILL,
|
||||
KernelEventKind.FULL_FILL,
|
||||
]
|
||||
),
|
||||
status=rng.choice(
|
||||
[
|
||||
VenueEventStatus.ACKED,
|
||||
VenueEventStatus.PARTIALLY_FILLED,
|
||||
VenueEventStatus.FILLED,
|
||||
]
|
||||
),
|
||||
venue_order_id=current.active_entry_order.venue_order_id,
|
||||
venue_client_id=current.active_entry_order.venue_client_id,
|
||||
side=current.side,
|
||||
asset=current.asset,
|
||||
price=current.entry_price or 100.0,
|
||||
size=current.size or 1.0,
|
||||
filled_size=current.size or 1.0,
|
||||
remaining_size=0.0,
|
||||
)
|
||||
kernel.on_venue_event(event)
|
||||
elif current.active_exit_order is not None:
|
||||
event = VenueEvent(
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
event_id=f"evt-{i}-{slot_id}",
|
||||
trade_id=current.trade_id,
|
||||
slot_id=slot_id,
|
||||
kind=rng.choice(
|
||||
[
|
||||
KernelEventKind.PARTIAL_FILL,
|
||||
KernelEventKind.FULL_FILL,
|
||||
KernelEventKind.CANCEL_ACK,
|
||||
KernelEventKind.CANCEL_REJECT,
|
||||
]
|
||||
),
|
||||
status=rng.choice(
|
||||
[
|
||||
VenueEventStatus.PARTIALLY_FILLED,
|
||||
VenueEventStatus.FILLED,
|
||||
VenueEventStatus.CANCELED,
|
||||
VenueEventStatus.CANCELED_REJECTED,
|
||||
]
|
||||
),
|
||||
venue_order_id=current.active_exit_order.venue_order_id,
|
||||
venue_client_id=current.active_exit_order.venue_client_id,
|
||||
side=current.side,
|
||||
asset=current.asset,
|
||||
price=current.entry_price or 100.0,
|
||||
size=current.size or 1.0,
|
||||
filled_size=min(current.size or 1.0, 0.5),
|
||||
remaining_size=max(0.0, (current.size or 1.0) - 0.5),
|
||||
)
|
||||
kernel.on_venue_event(event)
|
||||
|
||||
writer_slots = self._slot_dicts(self.writer)
|
||||
reader_slots = self._slot_dicts(self.reader)
|
||||
kernel_slots = [slot.to_dict() for slot in kernel.state.slots]
|
||||
|
||||
self.assertEqual(writer_slots, reader_slots)
|
||||
self.assertEqual(reader_slots, kernel_slots)
|
||||
self.assertEqual(self.reader.read_control().mode, kernel.control.mode)
|
||||
self.assertEqual(self.reader.read_control().verbosity, kernel.control.verbosity)
|
||||
self.assertEqual(len(self.reader.read_intents()), len(self.writer.read_intents()))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user