PINK kernel fix-of-fixes: slot-PnL repair plumbing
Review of PINK_ACCOUNTING_EXEC_FIX execution found the Phase 3.2 repair path triply broken: (1) !closed guard blocked repair on terminal fills — the common price-less case; (2) wrapper on_account_event was a raw FFI passthrough so repairs never settled into published capital; (3) live FILL_SETTLED carried no slot_id and realized_pnl=0 (pre-folded) — repair was dead code. Fixes: repair allowed on closed slots (flag+dedup keep it idempotent); wrapper settles the baseline diff on FILL_SETTLED-with-slot_id; dedicated repair_realized_pnl field avoids double-folding the K-ledger; _FakeKernelAccount fixture mirrors the Phase 1 anchor_to_exchange contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1156,7 +1156,33 @@ class ExecutionKernel:
|
||||
available_capital (E rules when present), k_capital, event_seq,
|
||||
capital_frozen (bool), duplicate_event (bool if deduplicated).
|
||||
"""
|
||||
return _get_rust().on_account_event(self._backend, event)
|
||||
result = _get_rust().on_account_event(self._backend, event)
|
||||
# Settle slot-level repairs into published capital. The Rust
|
||||
# FILL_SETTLED handler may add exchange realized PnL to a slot whose
|
||||
# exit leg booked 0 (price-less fill); the settle-baseline diff
|
||||
# otherwise only runs in on_venue_event, so a repair — especially on
|
||||
# an already-CLOSED slot (terminal fill, the common case) — would
|
||||
# never reach AccountProjection.capital.
|
||||
try:
|
||||
kind = str(event.get("kind", "") or "").upper()
|
||||
sid_raw = event.get("slot_id")
|
||||
if kind == "FILL_SETTLED" and sid_raw is not None:
|
||||
sid = int(sid_raw)
|
||||
if 0 <= sid < self.max_slots:
|
||||
slot = self._get_slot(sid)
|
||||
incremental = slot.realized_pnl - self._last_settled_pnl.get(sid, 0.0)
|
||||
if abs(incremental) > 1e-12:
|
||||
self.account.settle(incremental)
|
||||
self._last_settled_pnl[sid] = slot.realized_pnl
|
||||
self.account.observe_slots(
|
||||
[self._get_slot(i) for i in range(self.max_slots)]
|
||||
)
|
||||
current = self._get_slot(sid)
|
||||
self.projection.write_slot(current)
|
||||
self.zinc_plane.write_slot(current)
|
||||
except Exception:
|
||||
pass
|
||||
return result
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Snapshot / restore — session-to-session state continuity
|
||||
|
||||
Reference in New Issue
Block a user