VIOLET V2b: ScriptedVenue + ExecDeadlineDriver (event-driven TTL @sub-second)

exec_driver.py lifts PINK's TTL-resolution logic (_exec_after_submit /
_handle_expired_working, live-proven) into a standalone driver with
injected ports (router/submit/pump/slot_view/venue_flat/ref-price) and
replaces the 1s polling sweep with one DeadlineScheduler deadline per
working order. The driver is the TIMING authority (router clamps TTLs
>=0.5s — its internal deadline is vestigial here); the router stays the
POLICY authority. R1 preserved verbatim: exit TTL -> MARKET escalation on
the SAME trade_id; post-only reject -> schedule_in(0) through the one
shared resolution path; venue-truth requote gate fails safe.

scripted_venue.py subclasses MockVenueAdapter (zero shared edits) with
per-trade directives: IMMEDIATE_FILL / REST_THEN_FILL / REST_THEN_EXPIRE /
POST_ONLY_REJECT / CANCEL_REJECT / FILL_RACES_CANCEL; deferred fills
release through reconcile() (the production pump seam), never the 50ms
subscribe() poll.

17 new tests incl. full-kernel CANCEL->venue mapping, fill-races-cancel,
bounded retry chains, on_fill deadline cancellation, fail-safe probe.
Router 77 green untouched; shared files clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Codex
2026-06-13 00:18:54 +02:00
parent ba01b914ce
commit dfe7136404
4 changed files with 906 additions and 0 deletions

View File

@@ -0,0 +1,260 @@
"""V2b: ExecDeadlineDriver — TTL resolution semantics over fake-kernel ports.
The real ExecutionRouter and the real DeadlineScheduler are used; only the
kernel/venue side is faked so each path (skip, retry, exhaust, market,
exit escalation, fill races, rejected-instant, fail-safe gate) can be
forced deterministically. Kernel-integration runs live in V2c.
"""
from __future__ import annotations
import asyncio
import sys
sys.path.insert(0, "/mnt/dolphinng5_predict")
import pytest
from prod.clean_arch.dita_v2.exec_router import ExecConfig, ExecutionRouter
from prod.clean_arch.violet.clock import DeadlineScheduler, LatencyHistogram
from prod.clean_arch.violet.exec_driver import (
ExecDeadlineDriver,
ExecDriverPorts,
)
from prod.clean_arch.violet.domain import ExecDriverSettings
from prod.clean_arch.violet.test_violet_scripted_venue import _intent
TTL_MS = 30.0
class _FakeRuntime:
"""slot_view + submit + pump fakes the driver ports plug into."""
def __init__(self):
self.slot = ("", "IDLE", 0.0)
self.submitted = [] # KernelIntents the driver sent
self.pump_hook = None # optional callable run on each pump
self.flat = True
self.last_fill_ns = 0
async def submit_intent(self, intent):
self.submitted.append(intent)
return None
async def pump_events(self):
if self.pump_hook is not None:
self.pump_hook()
return 0
def ports(self, router):
return ExecDriverPorts(
router=router,
submit_intent=self.submit_intent,
pump_events=self.pump_events,
slot_view=lambda: self.slot,
venue_flat=lambda: self.flat,
last_own_fill_mono_ns=lambda: self.last_fill_ns,
reference_price=lambda asset: 100.0,
)
def _setup(style="maker_both", miss="skip", retries=1, exhaust="skip"):
rt = _FakeRuntime()
router = ExecutionRouter(ExecConfig(
style=style, entry_miss=miss, entry_retries=retries,
retry_exhaust=exhaust))
sched = DeadlineScheduler(jitter_hist=LatencyHistogram("jit"))
driver = ExecDeadlineDriver(
rt.ports(router), sched,
settings=ExecDriverSettings(ttl_override_ms=TTL_MS))
return rt, router, sched, driver
def _enter_plan(router, tid, px=100.0):
return router.plan_entry(trade_id=tid, asset="BTCUSDT",
position_side="SHORT", reference_price=px)
def _exit_plan(router, tid, px=100.0):
return router.plan_exit(trade_id=tid, asset="BTCUSDT",
position_side="SHORT", reference_price=px,
reason="TAKE_PROFIT")
async def _drive(driver, sched, body):
sched.start()
try:
await body()
assert await driver.drain(2.0), driver.snapshot()
finally:
await sched.stop()
@pytest.mark.asyncio
async def test_expire_skip_cancels_then_clears():
rt, router, sched, driver = _setup(miss="skip")
async def body():
plan = _enter_plan(router, "E1")
driver.on_submit(plan, _intent("E1", limit_price=plan.limit_price))
assert router.working("E1") is not None
await asyncio.sleep(TTL_MS / 1000 + 0.1)
await _drive(driver, sched, body)
cancels = [i for i in rt.submitted if i.intent_id == "E1-ttlcxl"]
assert len(cancels) == 1 and cancels[0].action.value == "CANCEL"
assert router.working_orders() == []
assert driver.counters["entry_skips"] == 1
assert driver.ttl_resolution_hist.count == 1
@pytest.mark.asyncio
async def test_retry_chain_then_exhaust_skip():
rt, router, sched, driver = _setup(miss="retry", retries=1, exhaust="skip")
async def body():
plan = _enter_plan(router, "E2")
driver.on_submit(plan, _intent("E2", limit_price=plan.limit_price))
await asyncio.sleep(2 * (TTL_MS / 1000) + 0.3) # two expiries
await _drive(driver, sched, body)
tids = [i.trade_id for i in rt.submitted if i.action.value == "ENTER"]
assert tids == ["E2-r1"] # exactly one retry
r1 = next(i for i in rt.submitted if i.trade_id == "E2-r1")
assert r1.order_type == "LIMIT"
assert r1.metadata["_time_in_force"] == "PostOnly"
assert driver.counters["entry_retries"] == 1
assert driver.counters["entry_skips"] == 1 # the exhaust
assert router.working_orders() == []
@pytest.mark.asyncio
async def test_exhaust_market_submits_market_enter():
rt, router, sched, driver = _setup(miss="retry", retries=0, exhaust="market")
async def body():
plan = _enter_plan(router, "E3")
driver.on_submit(plan, _intent("E3", limit_price=plan.limit_price))
await asyncio.sleep(TTL_MS / 1000 + 0.15)
await _drive(driver, sched, body)
markets = [i for i in rt.submitted if i.trade_id == "E3-m"]
assert len(markets) == 1
assert markets[0].order_type == "MARKET"
assert driver.counters["entry_markets"] == 1
@pytest.mark.asyncio
async def test_exit_expiry_escalates_market_same_trade_id():
rt, router, sched, driver = _setup()
rt.slot = ("X1", "POSITION_OPEN", 1.0) # position held by X1
async def body():
plan = _exit_plan(router, "X1")
assert plan.is_maker
driver.on_submit(plan, _intent("X1", limit_price=plan.limit_price))
await asyncio.sleep(TTL_MS / 1000 + 0.15)
await _drive(driver, sched, body)
mkt = [i for i in rt.submitted if i.intent_id == "X1-mkt"]
assert len(mkt) == 1
assert mkt[0].trade_id == "X1" # R1: SAME trade lifecycle
assert mkt[0].order_type == "MARKET"
assert mkt[0].metadata["_time_in_force"] == "GTC"
assert driver.counters["exit_market_fallbacks"] == 1
@pytest.mark.asyncio
async def test_fill_racing_cancel_is_noted_not_retried():
rt, router, sched, driver = _setup(miss="retry", retries=3)
fired = {"n": 0}
def pump_hook():
# The SECOND pump (after the cancel) reveals the fill won the race.
fired["n"] += 1
if fired["n"] >= 2:
rt.slot = ("E4", "POSITION_OPEN", 1.0)
rt.pump_hook = pump_hook
async def body():
plan = _enter_plan(router, "E4")
driver.on_submit(plan, _intent("E4", limit_price=plan.limit_price))
await asyncio.sleep(TTL_MS / 1000 + 0.15)
await _drive(driver, sched, body)
assert driver.counters["fills_after_ttl"] == 1
assert driver.counters["entry_retries"] == 0 # no re-quote after a fill
assert [i.trade_id for i in rt.submitted
if i.action.value == "ENTER"] == []
@pytest.mark.asyncio
async def test_on_fill_cancels_deadline_before_expiry():
rt, router, sched, driver = _setup()
async def body():
plan = _enter_plan(router, "E5")
driver.on_submit(plan, _intent("E5", limit_price=plan.limit_price))
driver.on_fill("E5") # WS fill notification
await asyncio.sleep(TTL_MS / 1000 + 0.1)
await _drive(driver, sched, body)
assert rt.submitted == [] # no cancel ever sent
assert driver.counters["deadline_fires"] == 0
assert router.working_orders() == []
@pytest.mark.asyncio
async def test_post_only_reject_resolves_instantly():
rt, router, sched, driver = _setup(miss="skip")
rt.slot = ("E6", "ORDER_REJECTED", 0.0)
async def body():
plan = _enter_plan(router, "E6")
driver.on_submit(plan, _intent("E6", limit_price=plan.limit_price))
await asyncio.sleep(0.05) # far below TTL
await _drive(driver, sched, body)
assert driver.counters["deadline_fires"] == 1 # schedule_in(0) fired now
assert any(i.intent_id == "E6-ttlcxl" for i in rt.submitted)
assert router.working_orders() == []
@pytest.mark.asyncio
async def test_requote_gate_fails_safe_on_probe_error():
rt, router, sched, driver = _setup(miss="retry", retries=2)
def boom():
raise RuntimeError("venue probe down")
driver.ports.venue_flat = boom
async def body():
plan = _enter_plan(router, "E7")
driver.on_submit(plan, _intent("E7", limit_price=plan.limit_price))
await asyncio.sleep(TTL_MS / 1000 + 0.15)
await _drive(driver, sched, body)
assert driver.counters["requote_blocked"] == 1
assert driver.counters["entry_retries"] == 0 # ambiguity ⇒ skip, never quote
assert router.working_orders() == []
@pytest.mark.asyncio
async def test_immediate_fill_never_registers():
rt, router, sched, driver = _setup()
rt.slot = ("E8", "POSITION_OPENED", 1.0)
async def body():
plan = _enter_plan(router, "E8")
driver.on_submit(plan, _intent("E8", limit_price=plan.limit_price))
await _drive(driver, sched, body)
assert driver.counters["immediate_fills"] == 1
assert router.working_orders() == []
assert driver.snapshot()["pending_deadlines"] == 0
if __name__ == "__main__":
raise SystemExit(pytest.main([__file__, "-v"]))