"""Rate-limit classification + downstream emission tests for PINK + DITAv2.""" from __future__ import annotations from datetime import datetime, timezone import unittest from prod.clean_arch.dita_v2 import ( ControlUpdate, ExecutionKernel, InMemoryControlPlane, InMemoryZincPlane, KernelCommandType, KernelDiagnosticCode, KernelIntent, KernelMode, MockVenueAdapter, MockVenueScenario, TradeSide, ) class TestRateLimitContract(unittest.TestCase): """Verify the kernel handles venue rejections without corrupting state.""" def setUp(self): self.control = InMemoryControlPlane() self.control.update(ControlUpdate( mode=KernelMode.DEBUG, trace_transitions=True, )) self.venue = MockVenueAdapter( MockVenueScenario( reject_entries=True, reject_exits=False, partial_fill_ratio=0.0, cancel_reject=False, ) ) self.kernel = ExecutionKernel( max_slots=1, control_plane=self.control, venue=self.venue, zinc_plane=InMemoryZincPlane(), ) def _make_intent(self, action: KernelCommandType = KernelCommandType.ENTER) -> KernelIntent: return KernelIntent( timestamp=datetime.now(timezone.utc), intent_id="rate-test-001", trade_id="rate-trade-001", slot_id=0, asset="BTCUSDT", side=TradeSide.SHORT, action=action, reference_price=65000.0, target_size=0.01, leverage=2.0, reason="rate_limit_test", ) def test_kernel_state_unaffected_by_rejection(self): """Slot returns to free/IDLE after venue rejects entry.""" intent = self._make_intent(KernelCommandType.ENTER) self.kernel.process_intent(intent) slot = self.kernel.slot(0) self.assertTrue(slot.is_free(), f"Slot should be free after reject, got {slot.fsm_state}") if __name__ == "__main__": unittest.main()