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>
2026-06-13 00:31:09 +02:00
|
|
|
"""VIOLET V2: ExecStormHarness — real kernel + ScriptedVenue + exec driver.
|
|
|
|
|
|
|
|
|
|
Composition root for the V2 scenario matrix and the V2 latency gate:
|
|
|
|
|
builds the production bundle (MOCK mode, injected ScriptedVenue), wires
|
|
|
|
|
the ExecDeadlineDriver ports, runs scripted synthetic-intent cycles, and
|
|
|
|
|
emits a gate report (ExecGateReport schema from domain.py) archived next
|
|
|
|
|
to the V0 reports.
|
|
|
|
|
|
|
|
|
|
The pump here is the production seam: venue.reconcile() → kernel
|
|
|
|
|
.on_venue_event, forwarding working-order FULL_FILLs to driver.on_fill —
|
|
|
|
|
exactly what the runtime's pump_venue_events does live.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import asyncio
|
|
|
|
|
import json
|
|
|
|
|
import platform
|
|
|
|
|
import time
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
from typing import Any, Dict, List, Optional, Tuple
|
|
|
|
|
|
|
|
|
|
from prod.clean_arch.dita_v2.contracts import KernelEventKind
|
|
|
|
|
from prod.clean_arch.dita_v2.exec_router import ExecConfig, ExecutionRouter
|
|
|
|
|
|
|
|
|
|
from .clock import DeadlineScheduler, LatencyHistogram, mono_ns
|
|
|
|
|
from .domain import ExecDriverSettings, ExecGateReport
|
|
|
|
|
from .exec_driver import ExecDeadlineDriver, ExecDriverPorts
|
|
|
|
|
from .harness import ReactorHarness, StormSpec
|
|
|
|
|
from .scripted_venue import ScriptedVenue
|
|
|
|
|
from .synthetic_intents import (
|
|
|
|
|
CycleOutcome,
|
|
|
|
|
IntentScriptSpec,
|
|
|
|
|
SyntheticIntentDriver,
|
|
|
|
|
generate_script,
|
|
|
|
|
outcomes_hash,
|
|
|
|
|
script_hash,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
REPORTS_DIR = Path("/mnt/dolphinng5_predict/prod/VIOLET_dev/reports")
|
|
|
|
|
|
|
|
|
|
GATE_JITTER_P99_MS = 25.0
|
|
|
|
|
GATE_TTL_RESOLUTION_P99_MS = 50.0
|
|
|
|
|
GATE_TTL_RESOLUTION_P50_MS = 10.0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ExecStormHarness:
|
|
|
|
|
def __init__(self, *, ttl_ms: float = 100.0, seed_capital: float = 25_000.0):
|
|
|
|
|
from prod.clean_arch.dita_v2.launcher import build_launcher_bundle
|
|
|
|
|
|
|
|
|
|
self.venue = ScriptedVenue()
|
|
|
|
|
bundle = build_launcher_bundle(venue_mode="MOCK", max_slots=1,
|
|
|
|
|
venue=self.venue)
|
|
|
|
|
self.kernel = bundle.kernel
|
|
|
|
|
if hasattr(self.kernel, "reset_and_seed"):
|
|
|
|
|
self.kernel.reset_and_seed(seed_capital)
|
|
|
|
|
self.seed_capital = seed_capital
|
|
|
|
|
|
|
|
|
|
self.router = ExecutionRouter(ExecConfig(style="maker_both"))
|
|
|
|
|
self.jitter_hist = LatencyHistogram("deadline_jitter")
|
|
|
|
|
self.scheduler = DeadlineScheduler(jitter_hist=self.jitter_hist)
|
|
|
|
|
self._last_fill_ns = 0
|
|
|
|
|
self.driver = ExecDeadlineDriver(
|
|
|
|
|
ExecDriverPorts(
|
|
|
|
|
router=self.router,
|
|
|
|
|
submit_intent=self.kernel.process_intent_async,
|
|
|
|
|
pump_events=self.pump,
|
|
|
|
|
slot_view=self.slot_view,
|
|
|
|
|
venue_flat=self._venue_flat,
|
|
|
|
|
last_own_fill_mono_ns=lambda: self._last_fill_ns,
|
|
|
|
|
reference_price=lambda asset: 0.0, # cycles fall back to limit px
|
|
|
|
|
),
|
|
|
|
|
self.scheduler,
|
|
|
|
|
# hot window 0: scripted cycles run back-to-back; the production
|
|
|
|
|
# hot-window guard has its own dedicated unit test.
|
|
|
|
|
settings=ExecDriverSettings(ttl_override_ms=ttl_ms,
|
|
|
|
|
requote_hot_window_ns=0),
|
|
|
|
|
)
|
|
|
|
|
self.synthetic = SyntheticIntentDriver(
|
|
|
|
|
kernel=self.kernel, venue=self.venue, driver=self.driver,
|
|
|
|
|
pump=self.pump, slot_view=self.slot_view, ttl_ms=ttl_ms)
|
|
|
|
|
self.ttl_ms = ttl_ms
|
|
|
|
|
|
|
|
|
|
# ── ports ─────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
def slot_view(self) -> Tuple[str, str, float]:
|
|
|
|
|
try:
|
|
|
|
|
slot = self.kernel.slot(0)
|
|
|
|
|
except Exception:
|
|
|
|
|
return "", "", 0.0
|
|
|
|
|
stage = getattr(slot, "fsm_state", None)
|
|
|
|
|
stage_name = getattr(stage, "value", None) or str(stage or "")
|
|
|
|
|
return (str(getattr(slot, "trade_id", "") or ""), str(stage_name),
|
|
|
|
|
float(getattr(slot, "size", 0.0) or 0.0))
|
|
|
|
|
|
|
|
|
|
def _venue_flat(self) -> bool:
|
|
|
|
|
for row in self.venue.open_positions() or []:
|
|
|
|
|
if abs(float(row.get("positionAmt") or 0.0)) > 1e-9:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
async def pump(self) -> int:
|
|
|
|
|
"""venue.reconcile() → kernel; forward working fills to the driver."""
|
|
|
|
|
events = self.venue.reconcile()
|
|
|
|
|
for ev in events:
|
|
|
|
|
self.kernel.on_venue_event(ev)
|
|
|
|
|
if ev.kind == KernelEventKind.FULL_FILL:
|
|
|
|
|
self._last_fill_ns = mono_ns()
|
|
|
|
|
if self.router.working(ev.trade_id) is not None:
|
|
|
|
|
self.driver.on_fill(ev.trade_id)
|
|
|
|
|
return len(events)
|
|
|
|
|
|
|
|
|
|
# ── runs ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
async def run_matrix(self, spec: IntentScriptSpec) -> List[CycleOutcome]:
|
|
|
|
|
self.scheduler.start()
|
|
|
|
|
try:
|
|
|
|
|
return await self.synthetic.run(spec)
|
|
|
|
|
finally:
|
|
|
|
|
await self.scheduler.stop()
|
|
|
|
|
|
|
|
|
|
async def run_gate(self, spec: IntentScriptSpec, *,
|
|
|
|
|
background_storm: Optional[StormSpec] = None,
|
|
|
|
|
beartype_meta: Optional[Dict[str, Any]] = None,
|
|
|
|
|
) -> ExecGateReport:
|
|
|
|
|
"""The V2 gate run: scenario cycles, optionally under the V0 storm
|
|
|
|
|
as background load (separate kernel — load, not interleaving)."""
|
|
|
|
|
storm_task = None
|
|
|
|
|
storm_harness = None
|
|
|
|
|
if background_storm is not None:
|
|
|
|
|
storm_harness = ReactorHarness() # own MOCK kernel
|
|
|
|
|
storm_task = asyncio.create_task(
|
|
|
|
|
storm_harness.run_storm(background_storm), name="bg_storm")
|
|
|
|
|
|
|
|
|
|
outcomes = await self.run_matrix(spec)
|
|
|
|
|
|
|
|
|
|
if storm_task is not None:
|
|
|
|
|
await storm_task
|
|
|
|
|
|
|
|
|
|
cycles = generate_script(spec)
|
|
|
|
|
ok_all = all(o.ok for o in outcomes)
|
|
|
|
|
scenarios: Dict[str, int] = {}
|
|
|
|
|
for o in outcomes:
|
|
|
|
|
scenarios[o.scenario] = scenarios.get(o.scenario, 0) + 1
|
|
|
|
|
jitter = self.jitter_hist.to_dict()
|
|
|
|
|
ttl_res = self.driver.ttl_resolution_hist.to_dict()
|
|
|
|
|
snap = self.driver.snapshot()
|
|
|
|
|
accounting_ok = self._accounting_ok()
|
|
|
|
|
|
|
|
|
|
passed = (
|
|
|
|
|
ok_all
|
|
|
|
|
and jitter["p99_ms"] < GATE_JITTER_P99_MS
|
|
|
|
|
and ttl_res["p99_ms"] < GATE_TTL_RESOLUTION_P99_MS
|
|
|
|
|
and ttl_res["p50_ms"] < GATE_TTL_RESOLUTION_P50_MS
|
|
|
|
|
and not self.router.working_orders()
|
|
|
|
|
and snap["pending_deadlines"] == 0
|
|
|
|
|
and accounting_ok
|
|
|
|
|
)
|
|
|
|
|
return ExecGateReport(
|
|
|
|
|
generated_utc=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
|
|
|
|
host=platform.node(),
|
|
|
|
|
script={**spec.to_dict(), "script_hash": script_hash(cycles),
|
|
|
|
|
"outcomes_hash": outcomes_hash(outcomes),
|
|
|
|
|
"outcomes": [o.key() | {"detail": o.detail}
|
|
|
|
|
for o in outcomes]},
|
|
|
|
|
cycles=len(outcomes),
|
|
|
|
|
scenarios=scenarios,
|
|
|
|
|
jitter=jitter,
|
|
|
|
|
ttl_resolution=ttl_res,
|
|
|
|
|
# The scheduler fires only when due <= now by construction; a
|
|
|
|
|
# negative jitter sample would be the contradiction.
|
|
|
|
|
early_fires=int(jitter.get("min_ms", 0.0) < 0.0),
|
|
|
|
|
stuck_orders=len(self.router.working_orders()),
|
|
|
|
|
pending_deadlines=snap["pending_deadlines"],
|
|
|
|
|
terminals_ok=ok_all,
|
|
|
|
|
accounting_ok=accounting_ok,
|
|
|
|
|
deterministic=True, # asserted by the test
|
|
|
|
|
beartype=beartype_meta or {},
|
|
|
|
|
passed=passed,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def _accounting_ok(self) -> bool:
|
VIOLET V2d: V2 exec gate PASSED on prod host + beartype ADOPT verdict
200 scenario cycles @100ms TTL with the V0 storm as concurrent background
load: deadline_jitter p99 8.47ms (<25, zero early fires), ttl_resolution
fire->CANCEL p99 5.89ms (<50) p50 0.08ms (<10), all terminals correct,
zero stuck orders/deadlines, capital never froze, run-to-run determinism
(identical outcomes_hash). V0 latency gate re-run: still PASSED.
beartype A/B (subprocess, import-time kill-switch): jitter p99 delta
+0.42ms, ttl p99 delta +0.025ms -> ADOPT (<1ms budget); 'typed' stays on
by default, DOLPHIN_VIOLET_BEARTYPE=0 escape hatch retained.
exec_harness: CLI runner (the A/B vehicle), is_capital_frozen() for the
accounting verdict, early-fires derived from negative jitter. Dedicated
non-gate test: full exec path vs ObserveOnlyVenue - inner venue untouched,
slot stays free. Violet suite 97 green; router 77 green; shared clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 00:48:38 +02:00
|
|
|
"""capital_frozen never set (the kernel's reconcile-gate verdict)."""
|
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>
2026-06-13 00:31:09 +02:00
|
|
|
try:
|
VIOLET V2d: V2 exec gate PASSED on prod host + beartype ADOPT verdict
200 scenario cycles @100ms TTL with the V0 storm as concurrent background
load: deadline_jitter p99 8.47ms (<25, zero early fires), ttl_resolution
fire->CANCEL p99 5.89ms (<50) p50 0.08ms (<10), all terminals correct,
zero stuck orders/deadlines, capital never froze, run-to-run determinism
(identical outcomes_hash). V0 latency gate re-run: still PASSED.
beartype A/B (subprocess, import-time kill-switch): jitter p99 delta
+0.42ms, ttl p99 delta +0.025ms -> ADOPT (<1ms budget); 'typed' stays on
by default, DOLPHIN_VIOLET_BEARTYPE=0 escape hatch retained.
exec_harness: CLI runner (the A/B vehicle), is_capital_frozen() for the
accounting verdict, early-fires derived from negative jitter. Dedicated
non-gate test: full exec path vs ObserveOnlyVenue - inner venue untouched,
slot stays free. Violet suite 97 green; router 77 green; shared clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 00:48:38 +02:00
|
|
|
return not bool(self.kernel.is_capital_frozen())
|
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>
2026-06-13 00:31:09 +02:00
|
|
|
except Exception:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def archive_report(report: ExecGateReport) -> Path:
|
|
|
|
|
REPORTS_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
name = f"violet_v2_exec_gate_{time.strftime('%Y%m%d_%H%M%S', time.gmtime())}.json"
|
|
|
|
|
path = REPORTS_DIR / name
|
|
|
|
|
path.write_text(json.dumps(report.model_dump(), indent=2, default=str))
|
|
|
|
|
return path
|
VIOLET V2d: V2 exec gate PASSED on prod host + beartype ADOPT verdict
200 scenario cycles @100ms TTL with the V0 storm as concurrent background
load: deadline_jitter p99 8.47ms (<25, zero early fires), ttl_resolution
fire->CANCEL p99 5.89ms (<50) p50 0.08ms (<10), all terminals correct,
zero stuck orders/deadlines, capital never froze, run-to-run determinism
(identical outcomes_hash). V0 latency gate re-run: still PASSED.
beartype A/B (subprocess, import-time kill-switch): jitter p99 delta
+0.42ms, ttl p99 delta +0.025ms -> ADOPT (<1ms budget); 'typed' stays on
by default, DOLPHIN_VIOLET_BEARTYPE=0 escape hatch retained.
exec_harness: CLI runner (the A/B vehicle), is_capital_frozen() for the
accounting verdict, early-fires derived from negative jitter. Dedicated
non-gate test: full exec path vs ObserveOnlyVenue - inner venue untouched,
slot stays free. Violet suite 97 green; router 77 green; shared clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 00:48:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
# ── CLI (subprocess vehicle for the beartype ON/OFF gate comparison) ──────────
|
|
|
|
|
|
|
|
|
|
def _amain(argv: Optional[List[str]] = None) -> int:
|
|
|
|
|
import argparse
|
|
|
|
|
import sys as _sys
|
|
|
|
|
|
|
|
|
|
from .domain import _beartype_enabled
|
|
|
|
|
|
|
|
|
|
ap = argparse.ArgumentParser(description="VIOLET V2 exec gate runner")
|
|
|
|
|
ap.add_argument("--cycles", type=int, default=60)
|
|
|
|
|
ap.add_argument("--seed", type=int, default=7)
|
|
|
|
|
ap.add_argument("--ttl-ms", type=float, default=100.0)
|
|
|
|
|
ap.add_argument("--storm-events", type=int, default=0)
|
|
|
|
|
ap.add_argument("--out", type=str, default="")
|
|
|
|
|
args = ap.parse_args(argv)
|
|
|
|
|
|
|
|
|
|
async def go() -> ExecGateReport:
|
|
|
|
|
h = ExecStormHarness(ttl_ms=args.ttl_ms)
|
|
|
|
|
storm = (StormSpec(n_events=args.storm_events)
|
|
|
|
|
if args.storm_events > 0 else None)
|
|
|
|
|
return await h.run_gate(
|
|
|
|
|
IntentScriptSpec(n_cycles=args.cycles, seed=args.seed),
|
|
|
|
|
background_storm=storm,
|
|
|
|
|
beartype_meta={"enabled": _beartype_enabled()},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
report = asyncio.run(go())
|
|
|
|
|
blob = json.dumps(report.model_dump(), indent=2, default=str)
|
|
|
|
|
if args.out:
|
|
|
|
|
Path(args.out).write_text(blob)
|
|
|
|
|
else:
|
|
|
|
|
_sys.stdout.write(blob + "\n")
|
|
|
|
|
return 0 if report.passed else 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
raise SystemExit(_amain())
|