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:
75
prod/tests/test_pink_ditav2_restart_reconcile.py
Normal file
75
prod/tests/test_pink_ditav2_restart_reconcile.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""Crash/restart reconcile convergence tests for PINK → DITAv2."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
import unittest
|
||||
|
||||
from prod.clean_arch.dita_v2 import (
|
||||
ExecutionKernel,
|
||||
InMemoryControlPlane,
|
||||
InMemoryZincPlane,
|
||||
KernelCommandType,
|
||||
KernelIntent,
|
||||
MockVenueAdapter,
|
||||
MockVenueScenario,
|
||||
TradeSide,
|
||||
TradeSlot,
|
||||
TradeStage,
|
||||
)
|
||||
|
||||
|
||||
class TestRestartReconcile(unittest.TestCase):
|
||||
"""Verify exchange-led state convergence after simulated crash/restart."""
|
||||
|
||||
def setUp(self):
|
||||
self.control = InMemoryControlPlane()
|
||||
self.venue = MockVenueAdapter() # deterministic mock
|
||||
self.kernel = ExecutionKernel(
|
||||
max_slots=2,
|
||||
control_plane=self.control,
|
||||
venue=self.venue,
|
||||
zinc_plane=InMemoryZincPlane(),
|
||||
)
|
||||
|
||||
def _enter_position(self) -> None:
|
||||
intent = KernelIntent(
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
intent_id="entry-001",
|
||||
trade_id="trade-001",
|
||||
slot_id=0,
|
||||
asset="BTCUSDT",
|
||||
side=TradeSide.SHORT,
|
||||
action=KernelCommandType.ENTER,
|
||||
reference_price=65000.0,
|
||||
target_size=0.01,
|
||||
leverage=2.0,
|
||||
reason="restart_test_entry",
|
||||
)
|
||||
self.kernel.process_intent(intent)
|
||||
|
||||
def test_entry_opens_slot(self):
|
||||
self._enter_position()
|
||||
slot = self.kernel.slot(0)
|
||||
self.assertTrue(slot.is_open(),
|
||||
f"Expected open slot after entry, got {slot.fsm_state}")
|
||||
|
||||
def test_reconcile_with_empty_does_not_crash(self):
|
||||
self._enter_position()
|
||||
# Reconcile with empty list — no-op
|
||||
outcome = self.kernel.reconcile_from_slots([])
|
||||
self.assertIsNotNone(outcome,
|
||||
"Reconcile should return an outcome")
|
||||
|
||||
def test_capital_seed_after_reconcile(self):
|
||||
self._enter_position()
|
||||
capital_before = self.kernel.account.snapshot.capital
|
||||
self.assertGreater(capital_before, 0)
|
||||
self.kernel.reconcile_from_slots([])
|
||||
capital_after = self.kernel.account.snapshot.capital
|
||||
self.assertEqual(capital_after, capital_before,
|
||||
"Capital should not change during reconcile")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user