VIOLET V2c: synthetic intent scripts + ExecStormHarness + 9-scenario matrix
synthetic_intents.py: seeded IntentScriptSpec -> CycleSpec scripts (script_hash + outcomes_hash determinism, V0 discipline); per-scenario router ExecConfig constructed directly (no env mutation); cycle executor runs full ENTER->terminal->flatten lifecycles with per-scenario terminal predicates and cycle-end invariants (working registry empty, driver drained, slot flat). exec_harness.py: composition root — production bundle (MOCK, injected ScriptedVenue), ExecDeadlineDriver ports wired, pump = venue.reconcile() -> kernel + driver.on_fill forwarding (the production seam), gate report via the ExecGateReport schema, archive next to V0 reports. scripted_venue.py amendment: MARKET orders never rest (venue realism — directives are keyed by trade_id and the R1 MARKET fallback shares the position's trade_id). Matrix green through the REAL kernel at 100ms TTL: immediate fill, rest-then-fill (deadline cancelled), fill-races-cancel (no retry), rest-expire-retry (-r1 opens), retry-exhaust skip|market, exit-expire -> MARKET same trade_id, post-only reject, cancel-reject (no strand). Two runs same seed -> identical outcomes_hash. Router 77 green; shared clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
119
prod/clean_arch/violet/test_violet_exec_scenarios.py
Normal file
119
prod/clean_arch/violet/test_violet_exec_scenarios.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""V2c: the full scenario matrix through the REAL kernel + ScriptedVenue +
|
||||
ExecDeadlineDriver at 100 ms TTL — plus run-to-run determinism."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, "/mnt/dolphinng5_predict")
|
||||
sys.path.insert(0, "/mnt/dolphinng5_predict/nautilus_dolphin")
|
||||
|
||||
import pytest
|
||||
|
||||
from prod.clean_arch.violet.exec_harness import ExecStormHarness
|
||||
from prod.clean_arch.violet.synthetic_intents import (
|
||||
IntentScriptSpec,
|
||||
Scenario,
|
||||
outcomes_hash,
|
||||
)
|
||||
|
||||
|
||||
def _run(spec: IntentScriptSpec):
|
||||
async def go():
|
||||
h = ExecStormHarness(ttl_ms=100.0)
|
||||
outcomes = await h.run_matrix(spec)
|
||||
return h, outcomes
|
||||
return asyncio.run(go())
|
||||
|
||||
|
||||
def _one(scenario: Scenario, seed=11):
|
||||
spec = IntentScriptSpec(n_cycles=1, seed=seed, scenarios=[scenario])
|
||||
h, outs = _run(spec)
|
||||
assert len(outs) == 1
|
||||
out = outs[0]
|
||||
assert out.ok, f"{scenario.value}: {out.detail}"
|
||||
return h, out
|
||||
|
||||
|
||||
def test_immediate_fill_cycle():
|
||||
h, out = _one(Scenario.IMMEDIATE_FILL)
|
||||
assert (out.entry_path, out.exit_path) == ("base", "urgent_market")
|
||||
assert h.driver.counters["immediate_fills"] == 1
|
||||
assert h.driver.counters["deadline_fires"] == 0
|
||||
|
||||
|
||||
def test_rest_then_fill_cancels_deadline():
|
||||
h, out = _one(Scenario.REST_THEN_FILL)
|
||||
assert out.entry_path == "base"
|
||||
assert h.driver.counters["deadline_fires"] == 0 # fill beat the TTL
|
||||
assert h.driver.counters["working_registered"] == 1
|
||||
|
||||
|
||||
def test_fill_races_cancel_is_fill_not_retry():
|
||||
h, out = _one(Scenario.FILL_RACES_CANCEL)
|
||||
assert out.entry_path == "base"
|
||||
assert h.driver.counters["fills_after_ttl"] == 1
|
||||
assert h.driver.counters["entry_retries"] == 0
|
||||
assert h.driver.counters["entry_markets"] == 0
|
||||
|
||||
|
||||
def test_rest_expire_retry_opens_r1():
|
||||
h, out = _one(Scenario.REST_EXPIRE_RETRY)
|
||||
assert out.entry_path == "r1"
|
||||
assert h.driver.counters["entry_retries"] == 1
|
||||
assert "-r1" in h.venue.submits[-2] # retry hit the venue
|
||||
|
||||
|
||||
def test_retry_exhaust_skip_ends_flat():
|
||||
h, out = _one(Scenario.RETRY_EXHAUST_SKIP)
|
||||
assert out.entry_path == "none" and out.exit_path == "none"
|
||||
assert h.driver.counters["entry_retries"] == 1 # one retry, then
|
||||
assert h.driver.counters["entry_skips"] == 1 # exhaust skip
|
||||
assert h.venue.open_orders() == []
|
||||
|
||||
|
||||
def test_retry_exhaust_market_opens_m():
|
||||
h, out = _one(Scenario.RETRY_EXHAUST_MARKET)
|
||||
assert out.entry_path == "m"
|
||||
assert h.driver.counters["entry_markets"] == 1
|
||||
|
||||
|
||||
def test_exit_expire_market_same_trade():
|
||||
h, out = _one(Scenario.EXIT_EXPIRE_MARKET)
|
||||
assert out.entry_path == "base"
|
||||
assert out.exit_path == "market_fallback"
|
||||
assert h.driver.counters["exit_market_fallbacks"] == 1
|
||||
# R1: the MARKET fallback reused the position's trade_id.
|
||||
base_tid = next(t for t in h.venue.submits if t.startswith("vsyn"))
|
||||
assert h.venue.submits.count(base_tid) >= 2 # entry + mkt exit
|
||||
|
||||
|
||||
def test_post_only_reject_resolves():
|
||||
h, out = _one(Scenario.POST_ONLY_REJECT)
|
||||
assert out.entry_path == "none"
|
||||
assert h.router.working_orders() == []
|
||||
|
||||
|
||||
def test_cancel_reject_never_strands():
|
||||
h, out = _one(Scenario.CANCEL_REJECT)
|
||||
assert out.entry_path == "none"
|
||||
assert h.router.working_orders() == []
|
||||
assert h.venue.open_orders() == [] # cleanup cancel landed
|
||||
|
||||
|
||||
def test_full_matrix_two_seeds_deterministic():
|
||||
spec = IntentScriptSpec(n_cycles=18, seed=7)
|
||||
h1, o1 = _run(spec)
|
||||
h2, o2 = _run(spec)
|
||||
assert all(o.ok for o in o1), [o.detail for o in o1 if not o.ok]
|
||||
assert outcomes_hash(o1) == outcomes_hash(o2) # run-to-run identical
|
||||
assert {o.scenario for o in o1} == {s.value for s in Scenario}
|
||||
# cycle-end invariants held globally
|
||||
assert h1.router.working_orders() == []
|
||||
assert h1.driver.snapshot()["pending_deadlines"] == 0
|
||||
assert h1._accounting_ok()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(pytest.main([__file__, "-v"]))
|
||||
Reference in New Issue
Block a user