diff --git a/prod/clean_arch/dita_v2/rust_backend.py b/prod/clean_arch/dita_v2/rust_backend.py index b9f4d07..694e8cd 100644 --- a/prod/clean_arch/dita_v2/rust_backend.py +++ b/prod/clean_arch/dita_v2/rust_backend.py @@ -668,6 +668,7 @@ class ExecutionKernel: self._backend = _get_rust().create(self.max_slots) self._control_snapshot = self.control_plane.read() self._last_settled_pnl: Dict[int, float] = {} + self._slot_was_closed: Dict[int, bool] = {} self.projection.write_control(self._control_snapshot) self.zinc_plane.update_control(self._control_snapshot) self.state = KernelStateView(self) @@ -796,6 +797,7 @@ class ExecutionKernel: self.state.refresh() if intent.action == KernelCommandType.ENTER and outcome.accepted: self._last_settled_pnl[intent.slot_id] = 0.0 + self._slot_was_closed[intent.slot_id] = False emitted_events = [] all_venue_transitions: List[KernelTransition] = [] if outcome.accepted and intent.action in {KernelCommandType.ENTER, KernelCommandType.EXIT}: @@ -943,6 +945,7 @@ class ExecutionKernel: self.state.refresh() if intent.action == KernelCommandType.ENTER and outcome.accepted: self._last_settled_pnl[intent.slot_id] = 0.0 + self._slot_was_closed[intent.slot_id] = False emitted_events: List[VenueEvent] = [] all_venue_transitions: List[KernelTransition] = [] if outcome.accepted and intent.action in {KernelCommandType.ENTER, KernelCommandType.EXIT}: @@ -1040,6 +1043,14 @@ class ExecutionKernel: if abs(incremental_pnl) > 1e-12: self.account.settle(incremental_pnl) self._last_settled_pnl[slot.slot_id] = slot.realized_pnl + # Increment trade_seq when a slot transitions from open → closed so + # the next ENTER gets a unique trade_id. Without this increment the + # intent engine always generates "…-T-000000000001" and the Rust FSM + # resets (not SLOT_BUSYs) the slot on every duplicate ENTER signal. + was_closed = self._slot_was_closed.get(slot.slot_id, True) + if slot.closed and not was_closed: + self.account.snapshot.trade_seq += 1 + self._slot_was_closed[slot.slot_id] = slot.closed slots = [self._get_slot(i) for i in range(self.max_slots)] self.account.observe_slots(slots) current = self._get_slot(slot.slot_id) @@ -1192,6 +1203,7 @@ class ExecutionKernel: "open_positions": self.account.snapshot.open_positions, "open_notional": self.account.snapshot.open_notional, "leverage": self.account.snapshot.leverage, + "trade_seq": self.account.snapshot.trade_seq, # V2 — kernel atomic K/E account (E rules; K is parallel check) "k_capital": rust_account.get("k_capital", self.account.snapshot.capital), "k_realized_pnl": rust_account.get("k_realized_pnl", self.account.snapshot.realized_pnl),