uv(pass-a-r1): K-purge — Rev-4-FINAL compliance. A1: reconcile_ok replaced by stateless per-event tripwire (tripwire_ok + tripwire_last_event_id on AccountStateSnapshot). Detection latency = 1 event. A2: ASEXAccountV2.k_capital -> _k_capital_internal. 6 acceptance tests.

This commit is contained in:
Codex
2026-07-09 17:17:29 +02:00
parent 519565965e
commit 3da5d8866d
4 changed files with 254 additions and 1 deletions

View File

@@ -0,0 +1,88 @@
"""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."""
self._wallet_balance = wallet_balance
self._available_margin = available_margin
self._used_margin = used_margin
self._e_live = True
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