exec(unified): drive loop §7 — PINK _handle_expired_working ported + audit build items
drive_loop.py transcribes pink_direct.py:1089 (the 10-step expiry sequence) warts-and-all against injected ports (ExecPort seam: clock+kernel+venue), so no ambient state (C1). Carries the scar tissue: pump-before-cancel, re-classify-after-cancel (fill races cancel), EXIT never strands→MARKET, slot-busy double-entry guard, fail-safe venue-truth requote gate. SEAM learnings preserved as referenced comments (zero-silent-suppression rule). Decimal sizes (H1). - working.py: WorkingRegistry + WorkingOrder, injected clock, rejected→expire_now (one shared path). contract.py: client_order_id_core(attempt) — unique per attempt (audit H4/FIX). - _constants.py: REQUOTE_HOT_WINDOW_S=5.0 (prov: 2026-06-10 double-entry). - inventory §6: audit build items BI-1..5 folded in. - test_drive_loop.py: 15 scar-tissue tests. Mutation-verified RED under exit-no-escalate (kills 3) and no-hot-window (kills double-entry guard). Full exec_unified suite: 77 green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
86
prod/exec_unified/working.py
Normal file
86
prod/exec_unified/working.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""Working-order registry — the state the drive loop sweeps (spec §7).
|
||||
|
||||
A ``WorkingOrder`` is a maker quote that did not terminally fill on submit: it is either
|
||||
resting on the book or was rejected (post-only that would have crossed). Both live here;
|
||||
the drive loop resolves them on a TTL sweep.
|
||||
|
||||
The registry reads time through an INJECTED clock (no ambient ``time.monotonic`` — C1
|
||||
venue-side portability, and deterministic tests). All sizes/prices are ``Decimal`` — the
|
||||
best-practice audit's H1: PINK used float, the port does not.
|
||||
|
||||
Provenance: pink_direct.py working-order lifecycle (register/expired/note_fill/note_cancel,
|
||||
L975-1046) + exec_router.py WorkingOrder registry. Audit BI-1 (attempt counter).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
from typing import Callable
|
||||
|
||||
from .contract import Side
|
||||
|
||||
|
||||
class Action(Enum):
|
||||
ENTER = "ENTER" # opens/increases a position (ACQUIRE urgency)
|
||||
EXIT = "EXIT" # decreases/closes (PROTECT/HARVEST/ROTATE/CATASTROPHIC)
|
||||
|
||||
|
||||
@dataclass
|
||||
class WorkingOrder:
|
||||
"""A maker quote in flight. Mutable: ``deadline`` and ``attempt`` evolve as the drive
|
||||
loop reprices/retries; identity is ``request_id``."""
|
||||
|
||||
request_id: str # this attempt's id (unique per attempt — audit H4)
|
||||
base_request_id: str # parent request (survives retries; FIX OrigClOrdID)
|
||||
asset: str
|
||||
side: Side
|
||||
action: Action
|
||||
limit_price: Decimal
|
||||
deadline: float # in injected-clock units; <= now() means "resolve me"
|
||||
created: float
|
||||
attempt: int = 0
|
||||
meta: dict = field(default_factory=dict)
|
||||
|
||||
|
||||
class WorkingRegistry:
|
||||
"""In-memory registry of working quotes, swept by the drive loop.
|
||||
|
||||
NOT persisted here — durable/atomic persistence is a venue-seam concern (audit BI-5:
|
||||
never /tmp; durable path + tmp-rename). This object is the hot, in-process view.
|
||||
"""
|
||||
|
||||
def __init__(self, clock: Callable[[], float]) -> None:
|
||||
self._clock = clock
|
||||
self._orders: dict[str, WorkingOrder] = {}
|
||||
|
||||
def register(self, wo: WorkingOrder) -> WorkingOrder:
|
||||
self._orders[wo.request_id] = wo
|
||||
return wo
|
||||
|
||||
def working(self, request_id: str) -> WorkingOrder | None:
|
||||
"""The working order for this id, or None if already resolved (fill/cancel raced)."""
|
||||
return self._orders.get(request_id)
|
||||
|
||||
def expired(self) -> list[WorkingOrder]:
|
||||
"""Every working order whose deadline has passed (snapshot — safe to mutate during)."""
|
||||
now = self._clock()
|
||||
return [wo for wo in list(self._orders.values()) if now >= wo.deadline]
|
||||
|
||||
def expire_now(self, request_id: str) -> None:
|
||||
"""Pull a quote's deadline to now so the next sweep resolves it through the ONE
|
||||
shared miss/escalation path (rejected post-only, or a venue CANCEL_ACK surfacing
|
||||
via reconcile). pink_direct.py:1010-1011, 1290-1292 — do NOT build a second path.
|
||||
"""
|
||||
wo = self._orders.get(request_id)
|
||||
if wo is not None:
|
||||
wo.deadline = self._clock()
|
||||
|
||||
def note_fill(self, request_id: str) -> None:
|
||||
self._orders.pop(request_id, None)
|
||||
|
||||
def note_cancel(self, request_id: str) -> None:
|
||||
self._orders.pop(request_id, None)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self._orders)
|
||||
Reference in New Issue
Block a user