Files
siloqy/prod/tests/test_dita_v2_hazelcast.py
Codex 3d7b00e28d 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>
2026-05-30 18:26:43 +02:00

197 lines
6.8 KiB
Python

from __future__ import annotations
from datetime import datetime, timezone
import unittest
from prod.clean_arch.dita_v2 import (
ControlUpdate,
ExecutionKernel,
HazelcastProjection,
KernelCommandType,
KernelControlSnapshot,
KernelIntent,
KernelMode,
KernelVerbosity,
MockVenueAdapter,
MockVenueScenario,
TradeSide,
TradeStage,
TradeSlot,
build_projection,
build_position_state_row,
)
from prod.clean_arch.dita_v2.hazelcast_projection import HazelcastProjector, HazelcastRowWriter
class CaptureSink:
def __init__(self) -> None:
self.rows: list[tuple[str, dict[str, object]]] = []
def __call__(self, name: str, row: dict[str, object]) -> None:
self.rows.append((name, dict(row)))
class FakeMap:
def __init__(self) -> None:
self.rows: dict[str, object] = {}
def put(self, key: str, value: object) -> None:
self.rows[key] = value
class FakeTopic:
def __init__(self) -> None:
self.messages: list[str] = []
def publish(self, message: str) -> None:
self.messages.append(message)
class FakeHazelcastClient:
def __init__(self) -> None:
self.maps: dict[str, FakeMap] = {}
self.topics: dict[str, FakeTopic] = {}
def get_map(self, name: str) -> FakeMap:
return self.maps.setdefault(name, FakeMap())
def get_topic(self, name: str) -> FakeTopic:
return self.topics.setdefault(name, FakeTopic())
class TestDITAv2Hazelcast(unittest.TestCase):
def test_build_position_state_row_has_compatibility_fields(self) -> None:
slot = TradeSlot(
slot_id=0,
trade_id="trade-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,
)
row = build_position_state_row(
slot,
KernelControlSnapshot(
mode=KernelMode.DEBUG,
verbosity=KernelVerbosity.TRACE,
runtime_namespace="dita_v2",
strategy_namespace="dita_v2",
event_namespace="dita_v2",
actor_name="ExecutionKernel",
exec_venue="bingx",
data_venue="binance",
ledger_authority="exchange",
),
)
for key in (
"runtime_namespace",
"strategy_namespace",
"event_namespace",
"actor_name",
"exec_venue",
"data_venue",
"ledger_authority",
"trade_id",
"asset",
"slot_id",
"fsm_state",
):
self.assertIn(key, row)
self.assertEqual(row["trade_id"], "trade-1")
self.assertEqual(row["fsm_state"], TradeStage.POSITION_OPEN.value)
def test_projection_sink_writes_blue_pink_compatible_rows(self) -> None:
sink = CaptureSink()
projection = HazelcastProjection(writer=sink)
control = KernelControlSnapshot(mode=KernelMode.DEBUG, verbosity=KernelVerbosity.TRACE)
projection.write_control(control)
slot = TradeSlot(
slot_id=1,
trade_id="trade-2",
asset="ETHUSDT",
side=TradeSide.LONG,
entry_price=50.0,
size=2.0,
initial_size=2.0,
leverage=3.0,
fsm_state=TradeStage.POSITION_OPEN,
)
projection.write_slot(slot)
self.assertGreaterEqual(len(sink.rows), 2)
control_name, control_row = sink.rows[0]
slot_name, slot_row = sink.rows[1]
self.assertEqual(control_name, "hz:dita_control")
self.assertEqual(slot_name, "hz:dita_active_slots")
self.assertEqual(control_row["mode"], KernelMode.DEBUG.value)
self.assertEqual(slot_row["trade_id"], "trade-2")
self.assertEqual(slot_row["runtime_namespace"], "dita_v2")
self.assertEqual(slot_row["ledger_authority"], "exchange")
def test_hazelcast_row_writer_routes_maps_and_topics(self) -> None:
client = FakeHazelcastClient()
writer = HazelcastRowWriter(client)
writer("hz:dita_active_slots", {"trade_id": "trade-3", "slot_id": 0})
writer("hz:dita_control", {"mode": "DEBUG"})
writer("hz:dita_trade_events", {"event_id": "evt-1", "trade_id": "trade-3"})
self.assertIn("trade-3", client.get_map("hz:dita_active_slots").rows)
self.assertIn("control", client.get_map("hz:dita_control").rows)
self.assertEqual(len(client.get_topic("hz:dita_trade_events").messages), 1)
def test_build_projection_uses_client_when_requested(self) -> None:
client = FakeHazelcastClient()
projection = build_projection(client=client, prefer_real_hazelcast=True)
projection.write_control(KernelControlSnapshot(mode=KernelMode.DEBUG, verbosity=KernelVerbosity.TRACE))
projection.write_slot(
TradeSlot(
slot_id=0,
trade_id="trade-4",
asset="BTCUSDT",
side=TradeSide.SHORT,
entry_price=100.0,
size=1.0,
initial_size=1.0,
leverage=2.0,
fsm_state=TradeStage.POSITION_OPEN,
)
)
self.assertIn("control", client.get_map("hz:dita_control").rows)
self.assertIn("trade-4", client.get_map("hz:dita_active_slots").rows)
def test_kernel_emits_projection_rows(self) -> None:
sink = CaptureSink()
kernel = ExecutionKernel(
control_plane=None,
venue=MockVenueAdapter(MockVenueScenario(emit_fill_on_submit=True, partial_fill_ratio=1.0)),
projection=HazelcastProjection(writer=sink),
)
kernel.update_control(ControlUpdate(mode=KernelMode.DEBUG, verbosity=KernelVerbosity.TRACE))
kernel.process_intent(
KernelIntent(
timestamp=datetime.now(timezone.utc),
intent_id="intent-1",
trade_id="trade-1",
slot_id=0,
asset="BTCUSDT",
side=TradeSide.SHORT,
action=KernelCommandType.ENTER,
reference_price=100.0,
target_size=1.0,
leverage=2.0,
exit_leg_ratios=(1.0,),
reason="TEST",
)
)
names = [name for name, _ in sink.rows]
self.assertIn("hz:dita_control", names)
self.assertIn("hz:dita_active_slots", names)
slot_rows = [row for name, row in sink.rows if name == "hz:dita_active_slots"]
self.assertTrue(any(row["trade_id"] == "trade-1" for row in slot_rows))
self.assertTrue(any(row["runtime_namespace"] == "dita_v2" for row in slot_rows))
if __name__ == "__main__":
unittest.main()