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

@@ -1035,13 +1035,29 @@ impl KernelCore {
// realized_pnl and clear the flag.
if let Some(slot_id) = parsed.get("slot_id").and_then(|v| v.as_u64()) {
let sid = slot_id as usize;
if sid < self.slots.len() && !self.slots[sid].closed {
// NOTE: closed slots MUST be repairable — the most common
// price-less leg is the TERMINAL fill, where the slot is
// already CLOSED by the time FILL_SETTLED arrives. The
// was_skipped flag + account-event dedup keep this
// idempotent; a `!closed` guard would permanently lose
// exactly the legs the repair exists for.
if sid < self.slots.len() {
let was_skipped = self.slots[sid].metadata
.get("realized_skipped_no_price")
.and_then(|v| v.as_bool())
.unwrap_or(false);
if was_skipped && realized.is_finite() && realized != 0.0 {
self.slots[sid].realized_pnl += realized;
// The K-fold field (`realized_pnl`) is 0 on the live
// path because PREDICTED_FILL already folded it — the
// slot repair uses its own field so the same number
// is never double-folded into k_realized_pnl.
// Falls back to `realized_pnl` for callers that only
// send the legacy shape.
let repair = parsed
.get("repair_realized_pnl")
.and_then(|v| v.as_f64())
.unwrap_or(realized);
if was_skipped && repair.is_finite() && repair != 0.0 {
self.slots[sid].realized_pnl += repair;
self.slots[sid].metadata.insert(
"realized_skipped_no_price".to_string(),
Value::Bool(false),

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