VIOLET V3.4b: launcher shadow live-factor wiring

This commit is contained in:
Codex
2026-06-16 15:14:57 +02:00
parent 16add44326
commit fb344318aa
4 changed files with 365 additions and 8 deletions

View File

@@ -0,0 +1,79 @@
"""VIOLET launcher shadow helpers for live BLUE factor sourcing.
These helpers stay separate from the launcher module so they can be unit-tested
without importing the full launcher import chain.
"""
from __future__ import annotations
import logging
import os
LOGGER = logging.getLogger(__name__)
def build_shadow_live_source(
*,
client_factory=None,
selector_factory=None,
source_factory=None,
scan_history_factory=None,
):
"""Create the read-only BLUE live-factor mirror for the shadow path."""
if client_factory is None or selector_factory is None or source_factory is None or scan_history_factory is None:
import hazelcast
from .alpha_wrappers import VioletAssetSelector
from .live_blue_source import LiveBlueScanHistory, source_live_blue_sizing_factors
client_factory = client_factory or (lambda: hazelcast.HazelcastClient(
cluster_name=os.environ.get("HZ_CLUSTER", "dolphin"),
cluster_members=[os.environ.get("HZ_HOST", "localhost:5701")],
))
selector_factory = selector_factory or VioletAssetSelector
source_factory = source_factory or source_live_blue_sizing_factors
scan_history_factory = scan_history_factory or LiveBlueScanHistory
client = client_factory()
return {
"client": client,
"scan_history": scan_history_factory(),
"selector": selector_factory(),
"live_source": source_factory,
}
def shadow_decision_step(
shadow: dict,
payload: dict,
*,
scan_number: int,
now_ns: int,
vel_div: float,
vol_ok: bool,
) -> bool:
"""Run one shadow decision against the live BLUE factor plane."""
shadow["engine"].observe(payload, scan_number)
live_source = shadow.get("live_source")
factors = None
if live_source is not None:
live_result = live_source(
shadow["client"],
scan_history=shadow["scan_history"],
selector=shadow["selector"],
)
shadow["last_live_source"] = live_result
factors = live_result.factors
if factors is None:
return False
decision = shadow["engine"].decide(
now_ns=now_ns,
scan_number=scan_number,
capital=shadow["capital"],
vel_div=vel_div,
vol_ok=vol_ok,
factors=factors,
)
if decision is None:
return False
return shadow["journal"].journal(decision, mono_ns=now_ns)

View File

@@ -0,0 +1,155 @@
"""V3.4b launcher shadow wiring — live BLUE factor plane is mandatory."""
from __future__ import annotations
import sys
from types import SimpleNamespace
sys.path.insert(0, "/mnt/dolphinng5_predict")
from prod.clean_arch.violet.decision_engine import ShadowDecision, SizingFactors
from prod.clean_arch.violet.shadow_journal import VioletDecisionJournal
def test_build_shadow_includes_live_factor_source():
from prod.clean_arch.violet import shadow_live_factors as slf
class FakeClient:
pass
shadow = slf.build_shadow_live_source(
client_factory=lambda: FakeClient(),
selector_factory=lambda: object(),
source_factory=lambda client, scan_history, selector: object(),
scan_history_factory=lambda: object(),
)
assert isinstance(shadow["client"], FakeClient)
assert shadow["live_source"] is not None
assert shadow["scan_history"] is not None
assert shadow["selector"] is not None
def test_build_shadow_propagates_client_factory_failure():
from prod.clean_arch.violet import shadow_live_factors as slf
try:
slf.build_shadow_live_source(
client_factory=lambda: (_ for _ in ()).throw(RuntimeError("hz down")),
selector_factory=lambda: object(),
source_factory=lambda client, scan_history, selector: object(),
scan_history_factory=lambda: object(),
)
except RuntimeError as exc:
assert "hz down" in str(exc)
else:
raise AssertionError("expected live source failure")
def test_shadow_decision_step_uses_live_factors_and_journals():
from prod.clean_arch.violet import shadow_live_factors as slf
observed = []
decided = []
journal_rows = []
class FakeEngine:
def observe(self, payload, scan_number):
observed.append((scan_number, payload["vel_div"]))
def decide(self, **kwargs):
decided.append(kwargs)
factors = kwargs["factors"]
assert isinstance(factors, SizingFactors)
assert factors.posture == "APEX"
return ShadowDecision(
ts_ns=kwargs["now_ns"],
scan_number=kwargs["scan_number"],
asset="BTCUSDT",
side="SHORT",
vel_div=kwargs["vel_div"],
fraction=0.2,
conviction_leverage=3.0,
notional_fraction=0.6,
target_exposure=41400.0,
ars_score=1.23,
bucket_idx=1,
actuated=True,
base_leverage=1.0,
dc_lev_mult=1.0,
regime_size_mult=1.0,
market_ob_mult=1.0,
esof_size_mult=1.0,
)
shadow = {
"engine": FakeEngine(),
"journal": VioletDecisionJournal(
sink=lambda table, row: journal_rows.append((table, row)),
session_id="sess",
),
"capital": 69_000.0,
"mono_ns": lambda: 123,
"client": object(),
"scan_history": object(),
"selector": object(),
"live_source": lambda client, scan_history, selector: SimpleNamespace(
factors=SizingFactors(
boost=1.4,
beta=0.2,
mc_scale=0.5,
esof_score=0.42,
ob_median_imbalance=0.12,
ob_agreement_pct=0.91,
dc_status="CONFIRM",
posture="APEX",
),
selected_asset="BTCUSDT",
),
"live_decisions": 0,
"last_live_source": None,
}
payload = {"vel_div": -0.031, "vol_ok": True}
ok = slf.shadow_decision_step(
shadow,
payload,
scan_number=7,
now_ns=123,
vel_div=-0.031,
vol_ok=True,
)
assert ok is True
assert observed == [(7, -0.031)]
assert decided and decided[0]["factors"].dc_status == "CONFIRM"
assert shadow["last_live_source"].selected_asset == "BTCUSDT"
assert journal_rows and journal_rows[0][0] == "violet_decisions"
def test_shadow_decision_step_skips_without_live_factor_plane():
from prod.clean_arch.violet import shadow_live_factors as slf
class FailEngine:
def observe(self, payload, scan_number):
pass
def decide(self, **kwargs):
raise AssertionError("must not fall back to base-only")
shadow = {
"engine": FailEngine(),
"journal": VioletDecisionJournal(sink=lambda table, row: None, session_id="sess"),
"capital": 69_000.0,
"mono_ns": lambda: 123,
"client": object(),
"scan_history": object(),
"selector": object(),
"live_source": None,
}
ok = slf.shadow_decision_step(
shadow,
{"vel_div": -0.031, "vol_ok": True},
scan_number=7,
now_ns=123,
vel_div=-0.031,
vol_ok=True,
)
assert ok is False