"""ASExAccountPublisher — single-writer account to ZincPlane. Wraps ASEXAccountV2 (or a test double) so that every account event (fill, funding, balance_update) first applies through ASEx, then builds an E-only AccountStateSnapshot and publishes it to the ZincPlane account region. Edge-triggered: no timer writes, no periodic re-stamp. Publishes RAW E, never K. """ from __future__ import annotations from typing import Any, List, Optional from .contracts import AccountStateSnapshot from .zinc_plane import InMemoryZincPlane class AccountPublisher: """Applies account events and publishes E snapshots to a ZincPlane. Rev-4-FINAL: E sole authority. tripwire_ok = stateless per-event check. reconcile_ok kept as compat alias. No KBlock fields cross the boundary. """ def __init__(self, plane: InMemoryZincPlane) -> None: self._plane = plane self._event_seq: int = 0 # Internal state tracking E values (simplified: mirrors EBlock fields) self._wallet_balance: float = 0.0 self._available_margin: float = 0.0 self._used_margin: float = 0.0 self._e_live: bool = False # Stateless tripwire: set by each event, never accumulated self._tripwire_ok: bool = True self._tripwire_last_event_id: str = "" def apply_fill(self, wallet_balance: float, available_margin: float, used_margin: float, reconcile_ok: bool = True, tripwire_ok: bool = True, tripwire_last_event_id: str = "") -> None: """Apply a fill event: update E fields, publish snapshot with tripwire.""" self._wallet_balance = wallet_balance self._available_margin = available_margin self._used_margin = used_margin self._e_live = True self._tripwire_ok = tripwire_ok self._tripwire_last_event_id = tripwire_last_event_id self._publish() def apply_funding(self, amount: float) -> None: """Apply a funding event: funding changes wallet_balance.""" self._wallet_balance += amount self._available_margin += amount self._e_live = True self._publish() def apply_balance_update(self, wallet_balance: float, available_margin: float, used_margin: float) -> None: """Apply a balance update: overwrite all E fields. Resets tripwire to True (no fill event = no tripwire assessment needed; defaults to healthy).""" self._wallet_balance = wallet_balance self._available_margin = available_margin self._used_margin = used_margin self._e_live = True self._tripwire_ok = True self._tripwire_last_event_id = '' self._publish() def _publish(self) -> None: self._event_seq += 1 import time snap = AccountStateSnapshot( wallet_balance=self._wallet_balance, available_margin=self._available_margin, used_margin=self._used_margin, event_seq=self._event_seq, mono_ns=int(time.monotonic_ns()), e_live=self._e_live, reconcile_ok=self._tripwire_ok, # compat alias tripwire_ok=self._tripwire_ok, tripwire_last_event_id=self._tripwire_last_event_id, ) # Publish RAW E — NEVER K self._plane.publish_account(snap) @property def plane(self) -> InMemoryZincPlane: return self._plane @property def event_seq(self) -> int: return self._event_seq