VIOLET V1c: observe-only launcher + hard guard + divergence monitor + service (DARK)
launch_dolphin_violet.py: own namespaces hard-set (CH dolphin_violet, HZ DOLPHIN_STATE_VIOLET/PNL, Zinc prefix violet, DOLPHIN-VIOLET-001); own credentials (BINGX_VIOLET_API_KEY/SECRET) — DARK idle with periodic WARNING until provisioned; CH preflight SELECT-probes the required tables and NEVER creates (DDL-before-code); kernel snapshot path repointed away from PINK's fixed /tmp/.pink_kernel_state.json; mainnet hard-disabled; observe loop never calls runtime.step(). ObserveOnlyVenue: submit/cancel raise ObserveOnlyViolation with full attribute delegation — the kernel's venue-submit-failure rollback converts a refusal into a synthetic REJECT (slot back to IDLE), proven against the real kernel. FeedDivergenceMonitor: per-asset scan-vs-venue divergence rows (bookTicker WS via prod/bingx/market_stream, REST fallback) with stale-mid suppression and plane seq propagation — the FET 0.2176-vs-0.1878 detector; runs even DARK (public data). Supervisord [program:dolphin_violet] autostart=false, no keys in conf by design. Violet package: 42 tests green + V0 gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
109
prod/clean_arch/violet/test_violet_dark_idle.py
Normal file
109
prod/clean_arch/violet/test_violet_dark_idle.py
Normal file
@@ -0,0 +1,109 @@
|
||||
"""V1: dark-idle behavior — no keys ⇒ idle loop, exec adapter never built."""
|
||||
|
||||
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
|
||||
|
||||
|
||||
def _clear_keys(monkeypatch):
|
||||
monkeypatch.delenv("BINGX_VIOLET_API_KEY", raising=False)
|
||||
monkeypatch.delenv("BINGX_VIOLET_SECRET_KEY", raising=False)
|
||||
|
||||
|
||||
def test_keys_present_detection(monkeypatch):
|
||||
import prod.launch_dolphin_violet as lv
|
||||
|
||||
_clear_keys(monkeypatch)
|
||||
assert lv._violet_keys_present() is False
|
||||
monkeypatch.setenv("BINGX_VIOLET_API_KEY", "k")
|
||||
assert lv._violet_keys_present() is False # secret still missing
|
||||
monkeypatch.setenv("BINGX_VIOLET_SECRET_KEY", "s")
|
||||
assert lv._violet_keys_present() is True
|
||||
monkeypatch.setenv("BINGX_VIOLET_API_KEY", " ")
|
||||
assert lv._violet_keys_present() is False # whitespace is absent
|
||||
|
||||
|
||||
def test_dark_run_never_builds_exec_adapter(monkeypatch):
|
||||
"""Without keys, run() must enter the dark loop and never construct the
|
||||
observe runtime (and therefore never the BingX exec adapter)."""
|
||||
import prod.launch_dolphin_violet as lv
|
||||
|
||||
_clear_keys(monkeypatch)
|
||||
monkeypatch.setenv("DOLPHIN_VIOLET_DARK_DIVERGENCE", "0") # strict idle
|
||||
monkeypatch.setattr(lv, "_preflight_clickhouse", lambda: [])
|
||||
|
||||
def boom():
|
||||
raise AssertionError("observe runtime must not be built while DARK")
|
||||
|
||||
monkeypatch.setattr(lv, "_build_observe_runtime", boom)
|
||||
|
||||
warnings: list[str] = []
|
||||
monkeypatch.setattr(
|
||||
lv.LOGGER, "warning", lambda msg, *a: warnings.append(msg % a if a else str(msg))
|
||||
)
|
||||
|
||||
async def drive():
|
||||
task = asyncio.ensure_future(lv.run())
|
||||
await asyncio.sleep(0.3) # boot path reaches the dark loop
|
||||
task.cancel()
|
||||
try:
|
||||
await task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
asyncio.run(drive())
|
||||
assert any("VIOLET DARK" in w for w in warnings), warnings
|
||||
|
||||
|
||||
def test_missing_tables_idles_dark_naming_apply_cmd(monkeypatch):
|
||||
import prod.launch_dolphin_violet as lv
|
||||
|
||||
_clear_keys(monkeypatch)
|
||||
monkeypatch.setattr(lv, "_preflight_clickhouse", lambda: ["violet_feed_divergence"])
|
||||
crits: list[str] = []
|
||||
monkeypatch.setattr(
|
||||
lv.LOGGER, "critical", lambda msg, *a: crits.append(msg % a if a else str(msg))
|
||||
)
|
||||
|
||||
async def drive():
|
||||
task = asyncio.ensure_future(lv.run())
|
||||
await asyncio.sleep(0.3)
|
||||
task.cancel()
|
||||
try:
|
||||
await task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
asyncio.run(drive())
|
||||
assert crits and "apply_violet_ddl.py" in crits[0]
|
||||
assert "violet_feed_divergence" in crits[0]
|
||||
|
||||
|
||||
def test_violet_env_hard_sets_namespaces_and_snapshot_path(monkeypatch):
|
||||
import prod.launch_dolphin_violet as lv
|
||||
import prod.clean_arch.runtime.pink_direct as pd
|
||||
|
||||
monkeypatch.setenv("DOLPHIN_STATE_MAP", "DOLPHIN_STATE_PINK") # poisoned env
|
||||
original = pd._KERNEL_STATE_PATH
|
||||
try:
|
||||
lv._apply_violet_env()
|
||||
import os
|
||||
|
||||
assert os.environ["DOLPHIN_STATE_MAP"] == "DOLPHIN_STATE_VIOLET"
|
||||
assert os.environ["DITA_V2_PREFIX"] == "violet"
|
||||
assert os.environ["DOLPHIN_BINGX_ALLOW_MAINNET"] == "0"
|
||||
# kernel snapshot file repointed away from PINK's fixed path
|
||||
assert pd._KERNEL_STATE_PATH == lv._KERNEL_STATE_PATH_VIOLET
|
||||
assert "pink" not in str(pd._KERNEL_STATE_PATH)
|
||||
finally:
|
||||
pd._KERNEL_STATE_PATH = original
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(pytest.main([__file__, "-v"]))
|
||||
Reference in New Issue
Block a user