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>
This commit is contained in:
1679
prod/VIOLET_dev/reports/violet_v2_exec_gate_20260612_223838.json
Normal file
1679
prod/VIOLET_dev/reports/violet_v2_exec_gate_20260612_223838.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -180,16 +180,11 @@ class ExecStormHarness:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _accounting_ok(self) -> bool:
|
def _accounting_ok(self) -> bool:
|
||||||
"""K==E reconciled and capital_frozen never set."""
|
"""capital_frozen never set (the kernel's reconcile-gate verdict)."""
|
||||||
try:
|
try:
|
||||||
snap = self.kernel.snapshot()
|
return not bool(self.kernel.is_capital_frozen())
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
if isinstance(snap, dict):
|
|
||||||
if snap.get("capital_frozen"):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
return not bool(getattr(snap, "capital_frozen", False))
|
|
||||||
|
|
||||||
|
|
||||||
def archive_report(report: ExecGateReport) -> Path:
|
def archive_report(report: ExecGateReport) -> Path:
|
||||||
@@ -198,3 +193,42 @@ def archive_report(report: ExecGateReport) -> Path:
|
|||||||
path = REPORTS_DIR / name
|
path = REPORTS_DIR / name
|
||||||
path.write_text(json.dumps(report.model_dump(), indent=2, default=str))
|
path.write_text(json.dumps(report.model_dump(), indent=2, default=str))
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
# ── 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())
|
||||||
|
|||||||
152
prod/clean_arch/violet/test_violet_v2_exec_gate.py
Normal file
152
prod/clean_arch/violet/test_violet_v2_exec_gate.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
"""V2d: the VIOLET V2 exec gate — run on the prod host.
|
||||||
|
|
||||||
|
Budgets (plan harmonic-jumping-plum, V2d):
|
||||||
|
deadline_jitter p99 < 25 ms, zero early fires (V0 budget under exec load)
|
||||||
|
ttl_resolution (fire → CANCEL submitted) p99 < 50 ms, p50 < 10 ms
|
||||||
|
every scenario cycle reaches its expected terminal
|
||||||
|
zero stuck working orders / pending deadlines; accounting never frozen
|
||||||
|
determinism: same seed ⇒ identical outcomes_hash, twice
|
||||||
|
beartype ON vs OFF: subprocess A/B, deltas recorded in the report meta
|
||||||
|
(permanent adoption iff p99 delta < 1 ms)
|
||||||
|
|
||||||
|
The observe-only guard test runs in the regular suite (not gate-marked):
|
||||||
|
the ExecDeadlineDriver pointed at an ObserveOnlyVenue must never reach the
|
||||||
|
inner venue.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
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 (
|
||||||
|
GATE_JITTER_P99_MS,
|
||||||
|
GATE_TTL_RESOLUTION_P50_MS,
|
||||||
|
GATE_TTL_RESOLUTION_P99_MS,
|
||||||
|
ExecStormHarness,
|
||||||
|
archive_report,
|
||||||
|
)
|
||||||
|
from prod.clean_arch.violet.harness import StormSpec
|
||||||
|
from prod.clean_arch.violet.synthetic_intents import (
|
||||||
|
IntentScriptSpec,
|
||||||
|
Scenario,
|
||||||
|
outcomes_hash,
|
||||||
|
)
|
||||||
|
|
||||||
|
REPO = "/mnt/dolphinng5_predict"
|
||||||
|
|
||||||
|
|
||||||
|
def _subprocess_gate(beartype: str, cycles: int = 60) -> dict:
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as f:
|
||||||
|
out = f.name
|
||||||
|
env = {**os.environ, "DOLPHIN_VIOLET_BEARTYPE": beartype,
|
||||||
|
"PYTHONPATH": f"{REPO}:{REPO}/nautilus_dolphin"}
|
||||||
|
proc = subprocess.run(
|
||||||
|
[sys.executable, "-m", "prod.clean_arch.violet.exec_harness",
|
||||||
|
"--cycles", str(cycles), "--out", out],
|
||||||
|
cwd=REPO, env=env, capture_output=True, text=True, timeout=600)
|
||||||
|
assert proc.returncode == 0, (
|
||||||
|
f"beartype={beartype} subprocess gate failed:\n{proc.stdout}\n{proc.stderr}")
|
||||||
|
blob = json.loads(Path(out).read_text())
|
||||||
|
os.unlink(out)
|
||||||
|
return blob
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gate
|
||||||
|
def test_v2_exec_gate():
|
||||||
|
# 1) beartype A/B (subprocesses — the kill-switch is import-time).
|
||||||
|
on = _subprocess_gate("1")
|
||||||
|
off = _subprocess_gate("0")
|
||||||
|
d_jit = on["jitter"]["p99_ms"] - off["jitter"]["p99_ms"]
|
||||||
|
d_ttl = on["ttl_resolution"]["p99_ms"] - off["ttl_resolution"]["p99_ms"]
|
||||||
|
beartype_meta = {
|
||||||
|
"on_jitter_p99_ms": on["jitter"]["p99_ms"],
|
||||||
|
"off_jitter_p99_ms": off["jitter"]["p99_ms"],
|
||||||
|
"on_ttl_p99_ms": on["ttl_resolution"]["p99_ms"],
|
||||||
|
"off_ttl_p99_ms": off["ttl_resolution"]["p99_ms"],
|
||||||
|
"delta_jitter_p99_ms": round(d_jit, 3),
|
||||||
|
"delta_ttl_p99_ms": round(d_ttl, 3),
|
||||||
|
"adopt": bool(d_jit < 1.0 and d_ttl < 1.0),
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2) main gate: 200 cycles @100ms TTL with the V0 storm as background
|
||||||
|
# load (its own MOCK kernel — load, not interleaving).
|
||||||
|
async def go():
|
||||||
|
h = ExecStormHarness(ttl_ms=100.0)
|
||||||
|
report = await h.run_gate(
|
||||||
|
IntentScriptSpec(n_cycles=200, seed=7),
|
||||||
|
background_storm=StormSpec(n_events=20_000),
|
||||||
|
beartype_meta=beartype_meta,
|
||||||
|
)
|
||||||
|
return report
|
||||||
|
|
||||||
|
report = asyncio.run(go())
|
||||||
|
path = archive_report(report)
|
||||||
|
print(f"\nV2 exec gate report → {path}")
|
||||||
|
print(json.dumps({"jitter": report.jitter, "ttl_resolution":
|
||||||
|
report.ttl_resolution, "beartype": report.beartype},
|
||||||
|
indent=2, default=str))
|
||||||
|
|
||||||
|
failed = [o for o in report.script["outcomes"] if not o["ok"]]
|
||||||
|
assert not failed, f"cycles failed: {failed[:5]}"
|
||||||
|
assert report.jitter["p99_ms"] < GATE_JITTER_P99_MS, report.jitter
|
||||||
|
assert report.early_fires == 0
|
||||||
|
assert report.ttl_resolution["p99_ms"] < GATE_TTL_RESOLUTION_P99_MS, \
|
||||||
|
report.ttl_resolution
|
||||||
|
assert report.ttl_resolution["p50_ms"] < GATE_TTL_RESOLUTION_P50_MS, \
|
||||||
|
report.ttl_resolution
|
||||||
|
assert report.stuck_orders == 0 and report.pending_deadlines == 0
|
||||||
|
assert report.accounting_ok
|
||||||
|
assert report.passed
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gate
|
||||||
|
def test_v2_gate_determinism():
|
||||||
|
"""Same seed ⇒ identical outcome projections, run twice fresh."""
|
||||||
|
def run_once():
|
||||||
|
async def go():
|
||||||
|
h = ExecStormHarness(ttl_ms=100.0)
|
||||||
|
return await h.run_matrix(IntentScriptSpec(n_cycles=36, seed=21))
|
||||||
|
return asyncio.run(go())
|
||||||
|
|
||||||
|
o1, o2 = run_once(), run_once()
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
def test_observe_only_venue_blocks_exec_driver():
|
||||||
|
"""Defense in depth: the whole V2 exec path pointed at an
|
||||||
|
ObserveOnlyVenue never reaches the inner venue — the kernel converts
|
||||||
|
the guard's refusal into a synthetic REJECT and the slot stays free."""
|
||||||
|
from prod.clean_arch.violet.observe_guard import ObserveOnlyVenue
|
||||||
|
from prod.clean_arch.violet.synthetic_intents import (
|
||||||
|
IntentScriptSpec as Spec,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def go():
|
||||||
|
h = ExecStormHarness(ttl_ms=100.0)
|
||||||
|
inner = h.venue
|
||||||
|
h.kernel.venue = ObserveOnlyVenue(inner)
|
||||||
|
outs = await h.run_matrix(
|
||||||
|
Spec(n_cycles=1, seed=3, scenarios=[Scenario.IMMEDIATE_FILL]))
|
||||||
|
return h, inner, outs
|
||||||
|
|
||||||
|
h, inner, outs = asyncio.run(go())
|
||||||
|
assert inner.submits == [] # NOTHING reached the venue
|
||||||
|
assert not outs[0].ok # cycle honestly failed
|
||||||
|
assert h.slot_view()[2] == 0.0 # no position materialized
|
||||||
|
assert h.router.working_orders() == [] # nothing left working
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([__file__, "-v", "-m", "gate"]))
|
||||||
Reference in New Issue
Block a user