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:
Codex
2026-06-12 14:58:30 +02:00
parent d280407327
commit 4929087f7a
4 changed files with 552 additions and 4 deletions

View File

@@ -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