exec(unified): UnifiedExecutor — initial-submit pipeline + S2 pain-fence
executor.py composes the built parts into one execute(request, snapshot): S-grade fence → router.decide → placer.pre_submit → submit → register working. The initial-submit half that complements DriveLoop's expiry half (analogue of pink_direct.py:1645-1700). Composition rulings encoded + tested: - S2/S3 pain-fence (§15.2): refused WHOLE, loudly, below T14 — never silently sliced. - placer declines (spread gate) → cross ONLY if urgency crosses on expiry; ACQUIRE ABANDONS (a missed entry is free, §4-1). Both mutation-verified RED. - TTL from urgency discipline: PROTECT 2s / ROTATE deadline_ms / ACQUIRE quote-lifetime. contract.py: SGrade enum (S0-S3) + s_grade/parent_request_id fields. _constants: MAKER_QUOTE_TTL_S. FIX (real bug, not just test): drive_loop._is_resolved EXIT was trade_id-based (a PINK artifact — PINK reused the position's trade_id for exits). The agnostic layer never gets the position id, so exit-done is now SIZE-based. Kept ENTER on clientOrderId match. Full exec_unified suite: 94 green, mutation-litmus verified. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,9 @@ OPENISH = frozenset({
|
||||
})
|
||||
# Stages that mean the position is gone. pink_direct.py:1106.
|
||||
CLOSED_STAGES = frozenset({"POSITION_CLOSED", "CLOSED", "TRADE_TERMINAL_WRITTEN", "IDLE"})
|
||||
# Stages that mean the venue rejected our order (post-only would cross, etc.).
|
||||
# pink_direct.py:1000. A rejected maker quote still registers → resolves via the TTL path.
|
||||
REJECTED_STAGES = frozenset({"ORDER_REJECTED", "EXIT_REJECTED"})
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -64,6 +67,12 @@ class ResubmitPlan:
|
||||
reduce_only: bool
|
||||
|
||||
|
||||
# The plan the venue receives is the same shape whether it is an initial submit (executor,
|
||||
# attempt 0) or a rebuilt retry/escalation (drive loop). "Resubmit" is the origin name;
|
||||
# OrderPlan is the role name the executor uses.
|
||||
OrderPlan = ResubmitPlan
|
||||
|
||||
|
||||
class ExecPort(Protocol):
|
||||
"""The single seam to kernel + venue. Fakeable; the loop touches the world ONLY here."""
|
||||
|
||||
@@ -103,11 +112,21 @@ class DriveLoop:
|
||||
|
||||
# ── classification ───────────────────────────────────────────────────────
|
||||
def _is_resolved(self, wo: WorkingOrder, slot: SlotView) -> bool:
|
||||
"""Entry filled or exit done, per kernel truth (pink _entry_filled/_exit_done)."""
|
||||
"""Entry filled or exit done, per kernel truth (pink _entry_filled/_exit_done, L1099).
|
||||
|
||||
ENTER: our entry filled — the slot carries OUR clientOrderId (the kernel tags the new
|
||||
position with it; clientOrderId echo is the best-practice fill key, audit H5) and shows
|
||||
size + an open stage.
|
||||
|
||||
EXIT: the position is gone — size drained or a closed stage. **Deliberately SIZE-based,
|
||||
not trade_id-based**: pink_direct.py:1105 could compare `slot_tid != wo.trade_id` only
|
||||
because it REUSED the position's trade_id for the exit intent. This layer is agnostic
|
||||
(contract §2) — the caller mints a fresh request_id for the exit and never hands us the
|
||||
position's id — so an exit is "done" iff the position closed, which is the size signal.
|
||||
"""
|
||||
if wo.action is Action.ENTER:
|
||||
return slot.trade_id == wo.request_id and slot.size > 0 and slot.stage in OPENISH
|
||||
return (slot.trade_id != wo.request_id or slot.size <= 0
|
||||
or slot.stage in CLOSED_STAGES)
|
||||
return slot.size <= 0 or slot.stage in CLOSED_STAGES
|
||||
|
||||
def after_submit(self, wo: WorkingOrder, *, rejected: bool) -> str:
|
||||
"""Classify a maker submit: filled-now / working / rejected. pink L975.
|
||||
|
||||
Reference in New Issue
Block a user